obj instanceof Class
instanceof
연산자를 통해 객체가 특정 클래스에 속하는지 아닌지 확인할 수 있고 상속 관계도 확인해준다
class Rabbit {}
let rabbit = new Rabbit();
alert(rabbit instanceof Rabbit); // true
obj
가 Class
에 속하거나 Class
를 상속받는 클래스에 속하면 true
가 반환된다
function Rabbit() {}
alert(new Rabbit() instanceof Rabbit); // true
instanceof
는 생성자 함수에서도 사용 가능
let arr = [1, 2, 3];
alert(arr instanceof Array); // true
alert(arr instance Object); // true
Array
같은 내장 클래스에도 사용 가능
👉arr
은 클래스 Object
에도 속한다는 점 (Array
는 프로토타입 기반으로 Object
를 상속받음)
instanceof
연산자는 프로토타입 체인을 거슬러 올라가며 인스턴스 여부나 상속 여부를 확인한다
⚡ 정적 메서드 Symbol.hasIntance
를 사용하면 직접 확인 로직을 설정할 수도 있다
// canEat 프로퍼티가 있으면 animal이라고 판단할 수 있도록
// instanceOf의 로직을 직접 설정
class Animal {
static [Symbol.hasInstance](obj) {
if (obj.canEat) return true;
}
}
let obj = { canEat: true };
alert(obj instanceof Animal); // true, Animal[Symbol.hasInstance](obj)가 호출됨
Symbol.hasIntance
가 구현되어 있다면, obj instanceof Class
문 실행 시 Class[Symbol.hasInstance](obj)
가 호출되고 호출 결과는 boolean 타입이어야한다 > 이런 규칙을 기반으로 instanceof
의 동작을 커스터마이징 할 수 있다obj.__proto__ === Class.prototype?
obj.__proto__.__proto__ === Class.prototype?
obj.__proto__.__proto__.__proto__ === Class.prototype?
...
// 이 중 하나라도 true라면 true를 반환
// 그렇지 않고 체인의 끝에 도달하면 false를 반환
Symbol.hasInstance
가 구현되어있지 않으므로 이럴 땐 일반적인 로직이 사용된다 👉 obj instanceOf Class
는 Class.prototype
이 obj
프로토타입 체인 상의 프로토타입 중 하나와 일치하는지 확인한다class Animal {}
class Rabbit extends Animal {}
let rabbit = new Rabbit();
alert(rabbit instanceof Animal); // true
// rabbit.__proto__ === Rabbit.prototype
// rabbit.__proto__.__proto__ === Animal.prototype (일치)
상속받은 클래스를 사용하는 경우엔 두 번째 단계에서 일치여부가 확인된다
타입 확인을 위해 쓰인다
명세서에 따르면, 객체에서 내장 toString
을 추출하는 것이 가능하다
이렇게 추출한 메서드는 모든 값을 대상으로 실행할 수 있다
호출 결과는 값에 따라 달라진다
[object Number]
[object Boolean]
null
- [object Null]
undefined
- [object Undefined]
[object Array]
// 편의를 위해 toString 메서드를 변수에 복사함
let objectToString = Object.prototype.toString;
// 아래 변수의 타입은?
let arr = [];
alert( objectToString.call(arr) ); // [object Array]
let s = Object.prototype.toString;
alert( s.call(123) ); // [object Number]
alert( s.call(null) ); // [object Null]
alert( s.call(alert) ); // [object Function]
call을 사용해 컨텍스트를 this = arr
로 설정하고 함수 objectToString
을 실행
toString
알고리즘은 내부적으로 this
를 검사하고 상응하는 결과를 반환한다
let user = {
[Symbol.toStringTag]: "User"
};
alert( {}.toString.call(user) ); // [object User]
특수 객체 프로퍼티 Symbol.toStringTag
를 사용하면 toString
의 동작을 커스터마이징 할 수 있다
// 특정 호스트 환경의 객체와 클래스에 구현된 toStringTag
alert( window[Symbol.toStringTag]); // Window
alert( XMLHttpRequest.prototype[Symbol.toStringTag] ); // XMLHttpRequest
alert( {}.toString.call(window) ); // [object Window]
alert( {}.toString.call(new XMLHttpRequest()) ); // [object XMLHttpRequest]
대부분의 호스트 환경은 자체 객체에 이와 유사한 프로퍼티를 구현해 놓고 있다
호스트 환경 고유 객체의 Symbol.toStringTag
값은 [object ...]
로 쌓여진 값과 동일하다
👉 'typeof' 연산자의 강력한 변형들 (toString
과 toStringTag
)은 원시 자료형뿐만 아니라 내장 객체에도 사용할 수 있으며 커스터마이징 할 수 있다
내장 객체의 타입 확인을 넘어서 타입을 문자열 형태로 받고 싶다면 instanceof
대신, {}.toString.call
을 사용하면 된다