一、介绍
The instanceof operator tests to see if the prototype property of a constructor appears anywhere in the prototype chain of an object.
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
简单来说,instanceof
是 JavaScript 中用于检查对象
是否是某个类的实例的运算符。它会检查对象的原型链是否包含指定类的原型。
二、原型链机制
在 HOW - 实现原型链和构造函数组合式继承 我们介绍过继承是如何实现的,这里贴出相关代码:
function Animal(name) {
this.name = name;
}
Animal.prototype.getName = function() {
return this.name;
}
Animal.prototype.makeSound = function() {
return "aooo~";
}
function Dog(name, breed) {
Animal.call(this, name); // 调用父类构造函数,继承父类的属性
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype); // 设置子类的原型为父类的实例,继承父类的方法
// Object.create
// function create(prototypeObj) {
// return { '__proto__': prototypeObj };
// }
Dog.prototype.constructor = Dog; // 修正子类的构造函数指向自身
// 子类可以覆盖父类的方法
Dog.prototype.makeSound = function() {
return "Dog barks";
};
通过代码可以发现,每一个构造函数,如 Animal 和 Dog,都有一个 prototype
原型对象,原型对象都包含一个指向构造函数的指针 constructor
,如 Dog.prototype.constructor = Dog
。
假如通过上述构造函数得到实例:
const animal = new Animal();
const dog = new Dog();
// new 实现
const myNew = (constructorFun, ...args) => {
// creates a new empty object
// points its prototype to the func's prototype object
// 这里又用到了 Object.create();
const obj = Object.create(constructorFun.prototype);
// Object.create
// function create(prototypeObj) {
// return { '__proto__': prototypeObj };
// }
const result = constructorFun.apply(obj, args);
return typeof result === 'object' && result !== null ? result : obj;
}
animal
结构如下:
dog 结构如下:
可以发现,实例中会包含一个指向其原型对象的内部指针 [[Prototype]]
。
因此,当让一个原型对象作为另一个原型对象的实例,即 Dog.prototype = Object.create(Animal.prototype);
,就会形成一个原型链。
图中 SuperType 和 SubType 即构造函数,Instance 为实例。
三、instanceof 具体实现
instanceof 底层实现可以简化为以下步骤:
- 获取对象的原型链
- 遍历原型链,直到找到原型链的尽头(即 null)或者找到指定的类的原型
- 如果找到了指定的类的原型,则返回 true,否则返回 false
class MyClass {};
const test = new MyClass();
console.log('test', test);
console.log(myInstanceof(test, MyClass)); // true
console.log(myInstanceof({}, Object)); // true
console.log(myInstanceof({}, Array)); // false
console.log(myInstanceof([], Object)); // true
console.log(myInstanceof([], Array)); // true
function myInstanceof(obj, target) {
let prototype = Object.getPrototypeOf(obj);
while (prototype !== null) {
if (prototype === target.prototype) {
return true;
}
prototype = Object.getPrototypeOf(prototype);
}
return false;
}