介绍
Try it
instanceof
运算符用于检测构造函数的 prototype
属性是否出现在某个实例对象的原型链上。
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
const auto = new Car('Honda', 'Accord', 1998);
console.log(auto instanceof Car);
// expected output: true
console.log(auto instanceof Object);
// expected output: true
语法
object instanceof constructor
- 参数
object
某个实例对象constructor
某个构造函数 - 描述
instanceof
运算符用来检测constructor.prototype
是否存在于参数object
的原型链上。
// 定义构造函数
function C() {}
function D() {}
var o = new C();
o instanceof C; // true, 因为 Object.getPrototypeOf(o) === C.prototype
o instanceof D; // false, 因为 D.prototype 不存在于 o 的原型链上
o instanceof Object; // true, 因为 Object.prototype.isPrototypeOf(o) === true
C.prototype instanceof Object // true,同上
C.prototype = {};
var o2 = new C();
o2 instanceof C; // true
o instanceof C; // false , 因为 C.prototype 指向了一个空对象,这个对象不在 o 的原型链上
D.prototype = new C(); // 继承
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true
需要注意的是,如果表达式obj instanceof Foo
返回true
,则并不意味着该表达式会永远返回true
,因为Foo.prototype
属性的值有可能会改变。另外一种情况下,原表达式的值也会改变,就是改变对象obj
的原型链的情况,虽然在目前的 ES 规范中,我们只能读取对象的原型而不能改变它,但借助于非标准的__proto__
伪属性,是可以实现的。
应用
检测对象是不是某个构造函数的实例
if (!(mycar instanceof Car)) {
throw new Error('mycar is not an instance of Car');
}
实现
思路
- 拿到当前类的原型,拿到实例对象的原型链
沿着实例对象原型链,查找是否存在类的原型,直到尽头
- 获取当前实例对象的原型,沿着原型链一直往上找
- 如果在原型链上找到了类的原型,则返回 true
- 如果直到
Object
的基类 null 都没有找到,则返回 false
代码
function myInstanceof (obj, constructor) {
let proto = Object.getPrototypeOf(obj); // 实例对象的原型
while (true) {
if (proto === null) { // 到达尽头
return false;
}
if (proto === constructor.prototype) { // 找到了
return true;
}
proto = Object.getPrototypeOf(proto); // 沿着原型链继续找
}
}
这里的Object.getPrototypeOf(obj)
可以使用obj.__proto__
代替。但是推荐使用Object.getPrototypeOf(obj)
,因为__proto__
已经被弃用了。