instanceof
연산자를 사용하면 객체가 특정 클래스에 속하는지 여부를 확인할 수 있습니다. 상속도 고려됩니다.
이러한 확인은 많은 경우에 필요할 수 있습니다. 예를 들어, 인수의 유형에 따라 인수를 다르게 처리하는 다형성 함수를 구축하는 데 사용할 수 있습니다.
구문은 다음과 같습니다.
obj 인스턴스 오브 클래스
obj
Class
에 속하거나 클래스에서 상속되는 경우 true
반환합니다.
예를 들어:
클래스 토끼 {} let Rabbit = new Rabbit(); // Rabbit 클래스의 객체인가요? 경고(Rabbit의 토끼 인스턴스); // 진실
생성자 함수에서도 작동합니다.
// 클래스 대신 함수 토끼() {} 경고( new Rabbit() 인스턴스of Rabbit ); // 진실
...그리고 Array
와 같은 내장 클래스를 사용하면 다음과 같습니다.
arr = [1, 2, 3]으로 설정합니다. 경고(배열 인스턴스 arr); // 진실 경고(객체 인스턴스 도착); // 진실
arr
도 Object
클래스에 속한다는 점에 유의하세요. 이는 Array
프로토타입적으로 Object
에서 상속되기 때문입니다.
일반적으로, instanceof
확인을 위해 프로토타입 체인을 검사합니다. 정적 메서드 Symbol.hasInstance
에서 사용자 정의 논리를 설정할 수도 있습니다.
obj instanceof Class
의 알고리즘은 대략 다음과 같이 작동합니다.
정적 메소드 Symbol.hasInstance
가 있는 경우 Class[Symbol.hasInstance](obj)
로 호출하면 됩니다. true
또는 false
반환해야 하며, 완료됩니다. 이것이 바로 우리가 instanceof
의 동작을 사용자 정의할 수 있는 방법입니다.
예를 들어:
// 다음을 가정하는 instanceOf 검사를 설정합니다. // canEat 속성이 있는 모든 것은 동물입니다. 클래스 동물 { 정적 [Symbol.hasInstance](obj) { if (obj.canEat)는 true를 반환합니다. } } let obj = { canEat: true }; 경고(동물의 개체 인스턴스); // true: Animal[Symbol.hasInstance](obj)가 호출됩니다.
대부분의 클래스에는 Symbol.hasInstance
없습니다. 이 경우 표준 논리가 사용됩니다. obj instanceOf Class
Class.prototype
obj
프로토타입 체인의 프로토타입 중 하나와 동일한지 확인합니다.
즉, 하나씩 비교하십시오.
obj.__proto__ === Class.prototype? obj.__proto__.__proto__ === Class.prototype? obj.__proto__.__proto__.__proto__ === Class.prototype? ... // 답이 참이면 참을 반환합니다. // 그렇지 않고 체인의 끝에 도달하면 false를 반환합니다.
위의 예에서는 rabbit.__proto__ === Rabbit.prototype
이므로 즉시 답변을 제공합니다.
상속의 경우 두 번째 단계에서 일치가 이루어집니다.
클래스 동물 {} Rabbit 클래스는 Animal {}를 확장합니다. let Rabbit = new Rabbit(); 경고(동물의 토끼 인스턴스); // 진실 // Rabbit.__proto__ === Animal.prototype (일치 없음) // Rabbit.__proto__.__proto__ === Animal.prototype (일치!)
다음은 rabbit instanceof Animal
Animal.prototype
과 비교되는 그림입니다.
그건 그렇고, objA
objB
의 프로토타입 체인 어딘가에 있으면 true
반환하는 objA.isPrototypeOf(objB) 메서드도 있습니다. 따라서 obj instanceof Class
테스트는 Class.prototype.isPrototypeOf(obj)
로 바꿔 표현할 수 있습니다.
웃긴데 Class
생성자 자체는 검사에 참여하지 않습니다! 프로토타입 체인과 Class.prototype
만이 중요합니다.
객체가 생성된 후 prototype
속성이 변경되면 흥미로운 결과가 발생할 수 있습니다.
여기처럼:
함수 토끼() {} let Rabbit = new Rabbit(); // 프로토타입을 변경했습니다. Rabbit.prototype = {}; // ...더 이상 토끼가 아닙니다! 경고( Rabbit 인스턴스의 Rabbit ); // 거짓
우리는 일반 객체가 [object Object]
로 문자열로 변환된다는 것을 이미 알고 있습니다.
obj = {}로 놔두세요; 경고(obj); // [객체 객체] 경고(obj.toString()); //동일
이것이 toString
구현입니다. 그러나 실제로 toString
그보다 훨씬 더 강력하게 만드는 숨겨진 기능이 있습니다. 우리는 이것을 확장된 typeof
로 사용할 수 있고, instanceof
의 대안으로 사용할 수 있습니다.
이상하게 들리나요? 물론. 신비를 풀자.
사양에 따라 내장 toString
객체에서 추출하여 다른 값의 컨텍스트에서 실행할 수 있습니다. 그리고 그 결과는 그 값에 따라 달라집니다.
숫자의 경우 [object Number]
가 됩니다.
부울의 경우 [object Boolean]
이 됩니다.
null
의 경우: [object Null]
undefined
경우: [object Undefined]
배열의 경우: [object Array]
...등(사용자 정의 가능).
다음을 보여드리겠습니다.
// 편의를 위해 toString 메소드를 변수에 복사합니다. let objectToString = Object.prototype.toString; // 이것은 어떤 유형입니까? arr = []; 경고( objectToString.call(arr) ); // [객체 배열]
여기에서는 데코레이터 및 전달 장에 설명된 대로 call을 사용하고 this=arr
컨텍스트에서 objectToString
함수를 실행하기 위해 call/apply를 사용했습니다.
내부적으로 toString
알고리즘은 this
검사하고 해당 결과를 반환합니다. 더 많은 예:
let s = Object.prototype.toString; 경고( s.call(123) ); // [객체 번호] 경고( s.call(null) ); // [객체 널] 경고( s.call(alert) ); // [객체 함수]
Object toString
의 동작은 특수 객체 속성인 Symbol.toStringTag
사용하여 사용자 정의할 수 있습니다.
예를 들어:
사용자 = { [Symbol.toStringTag]: "사용자" }; 경고( {}.toString.call(user) ); // [객체 사용자]
대부분의 환경별 개체에는 이러한 속성이 있습니다. 다음은 몇 가지 브라우저별 예입니다.
// 환경별 개체 및 클래스에 대한 toStringTag: 경고(window[Symbol.toStringTag]); // 창문 경고( XMLHttpRequest.prototype[Symbol.toStringTag] ); // XMLHttp요청 경고( {}.toString.call(window) ); // [객체 창] 경고({}.toString.call(new XMLHttpRequest()) ); // [객체 XMLHttpRequest]
보시다시피 결과는 정확히 [object ...]
로 래핑된 Symbol.toStringTag
(존재하는 경우)입니다.
결국 우리는 원시 데이터 유형뿐만 아니라 내장 객체에도 작동하고 심지어 사용자 정의할 수도 있는 "스테로이드의 typeof"를 갖게 되었습니다.
단순히 확인하기보다는 유형을 문자열로 가져오려는 경우 내장 객체에 대해 instanceof
대신 {}.toString.call
사용할 수 있습니다.
우리가 알고 있는 유형 검사 방법을 요약해 보겠습니다.
위해 일한다 | 보고 | |
---|---|---|
typeof | 프리미티브 | 끈 |
{}.toString | 기본 요소, 내장 개체, Symbol.toStringTag 가 있는 개체 | 끈 |
instanceof | 사물 | 참/거짓 |
보시다시피, {}.toString
은 기술적으로 "더 발전된" typeof
입니다.
그리고 instanceof
연산자는 클래스 계층 구조로 작업하고 상속을 고려하여 클래스를 확인하려고 할 때 정말 빛납니다.
중요도: 5
아래 코드에서 instanceof
true
반환하는 이유는 무엇입니까? a
B()
에 의해 생성되지 않는다는 것을 쉽게 알 수 있습니다.
함수 A() {} 함수 B() {} A.prototype = B.prototype = {}; a = new A(); 경고(B 인스턴스); // 진실
응, 정말 이상한 것 같아.
그러나 instanceof
함수에 관심을 두지 않고 오히려 프로토타입 체인과 일치하는 prototype
에 관심을 갖습니다.
그리고 여기 a.__proto__ == B.prototype
이므로, instanceof
true
반환합니다.
따라서, instanceof
논리에 따라 prototype
실제로 생성자 함수가 아닌 유형을 정의합니다.