在 JavaScript 中,instanceof 操作符用于检查一个对象是否是某个构造函数的实例。具体来说,它用来判断对象的原型链中是否存在构造函数的 prototype 属性。

instanceof 的实现原理

instanceof 操作符的基本原理是基于原型链的逐层查找过程:

  1. 对象的 __proto__ 指针:每个对象在创建时会自动关联到某个原型对象,这个原型对象通过对象的 __proto__ 指针来引用。

  2. 构造函数的 prototype 属性:每个构造函数(如 ArrayObject)都有一个 prototype 属性,指向一个原型对象。这个原型对象包含了所有实例共享的属性和方法。

  3. 原型链查找instanceof 会从目标对象的 __proto__ 开始,沿着原型链一级一级查找,看是否能够找到构造函数的 prototype 属性所指向的那个原型对象。

  4. 返回结果:如果在原型链中找到构造函数的 prototype 属性,instanceof 返回 true,否则返回 false

代码示例

1
2
3
4
5
function Person() {}
const john = new Person();

console.log(john instanceof Person); // true
console.log(john instanceof Object); // true

在这个例子中:

  • Person 是一个构造函数,它的 prototype 属性指向 {}(一个空的对象)。
  • john 是通过 Person 构造函数创建的实例。
  • john__proto__ 指针指向 Person.prototype
  • john instanceof Person 会沿着 john.__proto__ 查找,发现它指向 Person.prototype,所以返回 true
  • 因为 Person.prototype 的原型是 Object.prototype,所以 john instanceof Object 也返回 true

instanceof 的内部实现过程

假设我们要判断 object instanceof Constructor

  1. 取得 object 的原型,赋值给一个变量 proto,即 proto = object.__proto__
  2. 取得 Constructorprototype 属性,赋值给 prototype
  3. 循环检查 proto 是否严格等于 prototype
    • 如果相等,则返回 true
    • 如果 protonull,说明到达原型链的顶端,还未找到,返回 false
    • 否则,继续沿着原型链查找,更新 proto = proto.__proto__

实现一个简单的 instanceof

我们可以用 JavaScript 模拟实现 instanceof 的基本逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function myInstanceof(object, constructor) {
let proto = object.__proto__;
const prototype = constructor.prototype;

while (proto) {
if (proto === prototype) {
return true;
}
proto = proto.__proto__;
}

return false;
}

// 测试
console.log(myInstanceof(john, Person)); // true
console.log(myInstanceof(john, Object)); // true
console.log(myInstanceof(john, Array)); // false

特殊情况

  1. 原始类型:对于 nullundefinedinstanceof 无法使用,因为它们没有原型链,会直接返回 false
  2. 自定义类型继承:如果构造函数的 prototype 被重新赋值为其他对象,实例也会相应受到影响,instanceof 结果会发生变化。
1
2
3
4
5
6
function Animal() {}
const dog = new Animal();
console.log(dog instanceof Animal); // true

Animal.prototype = {};
console.log(dog instanceof Animal); // false

小结

instanceof 的原理在于通过原型链逐层查找,将对象的 __proto__ 与构造函数的 prototype 进行比对。因此,instanceof 能准确判断对象和构造函数的继承关系,只要 prototype 没有被修改。