instanceof 操作符的原理及手写
instanceof 是什么
instanceof
用于检测一个对象是不是另一个对象的实例。
用法
obj instanceof Class
- 如果
obj
隶属于Class
类(或Class
类的子类),则返回true
。例如:
class Rabit {};
let rabit = new Rabit();
// rabit 是 Rabit 类的对象吗?
console.log(rabit instanceof Rabit); // true
instanceof
还适用于检测父类。
class Animal { };
class Rabit extends Animal { };
let rabit = new Rabit();
// rabit 是 Animal 子类的对象吗?
console.log(rabit instanceof Animal); // true
// 判断对象实例的原型对象和类的原型对象是否一致可以确定obj是该类的实例还是父类的实例
console.log(Object.getPrototypeOf(rabit) === Animal.prototype); // false
- 当然它也适用于构造函数的写法。
function Animal() { };
function Rabit() { };
let ani = new Animal();
Rabit.prototype = ani; // 原型继承
let rabit = new Rabit();
let animal = new Animal();
console.log(rabit instanceof Rabit); // true
console.log(rabit instanceof Animal); // true
instanceof
只能正确判断引用数据类型,而不能正确判断基本数据类型。
console.log(2 instanceof Number); // false
console.log(true instanceof Boolean); // false
console.log('str' instanceof String); // false
console.log([] instanceof Array); // true
console.log(function(){} instanceof Function); // true
console.log({} instanceof Object); // true
基本数据类型不具备对象的特征,没有原型链可言,所以无法通过 instanceof
判断,应该使用 typeof
。
实现原理
instanceof
的工作原理就是判断在一个对象原型链中能否找到该类型(构造函数)的原型。
它会顺着原型链依次去比较,直到obj.__prototype__ === Class.prototype
为止。
obj.__proto__ === Class.prototype?
obj.__proto__.__proto__ === Class.prototype?
obj.__proto__.__proto__.__proto__ === Class.prototype?
...
// 如果任意一个的答案为 true,则返回 true
// 否则,如果我们已经检查到了原型链的尾端,则返回 false
像前面提到的 rabit instanceof Animal
这个例子,它会先和自身的原型对象匹配,再一直顺着原型链去和父类的原型对象匹配:
class Animal {}
class Rabbit extends Animal {}
let rabbit = new Rabbit();
alert(rabbit instanceof Animal); // true
// rabbit.__proto__ === Animal.prototype(无匹配)
// rabbit.__proto__.__proto__ === Animal.prototype(匹配!)
下图展示了 rabbit instanceof Animal
的执行过程中,Animal.prototype
是如何参与比较的:
手写instanceof
既然我们已经理解了原理,那么就来试试动手实现一个 Instanceof
吧。
// left传入obj,right传入类
function myInstanceof(left, right) {
// 遇到基本数据类型直接返回false,有些博客都漏了这一步
if (typeof left !== 'object' || typeof left !== 'function' || left === null) {
return false;
};
// 也可以通过Object.getPrototypeOf(left)拿到原型对象
let proto = left.__proto__;
let prototype = right.prototype;
while (true) {
// 已经到原型链尽头null
if (!proto) return false;
// 匹配,返回true
if (proto === prototype) return true;
// 顺着原型链更新指针
proto = proto.__proto__;
}
}
测试:
function myInstanceof(left, right) {
// 遇到基本数据类型直接返回false,有些博客都漏了这一步
if (typeof left !== 'object' || typeof left !== 'function' || left === null) {
return false;
};
// 也可以通过Object.getPrototypeOf(left)拿到原型对象
let proto = left.__proto__;
let prototype = right.prototype;
while (true) {
// 已经到原型链尽头null
if (!proto) return false;
// 匹配,返回true
if (proto === prototype) return true;
// 顺着原型链更新指针
proto = proto.__proto__;
}
}
console.log(myInstanceof(function () {}, Function)); // true
console.log(myInstanceof({}, Object)); // true
console.log(myInstanceof([], Function)); // false
console.log(myInstanceof(1, Number)); // false
如有问题欢迎在评论区讨论,一起进步!
转载自:https://juejin.cn/post/7342332602575437875