Skip to content

1. 核心概念 (Core Concept)

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。它本质上是一种原型链关系的检测。

2. 为什么需要它? (The "Why")

  • 类型判断的局限性: typeof 运算符对于复杂类型(如对象、数组、null)的判断不够精确,无法区分不同的对象类型。
  • 原型链关系的检测: 在面向对象编程中,需要判断一个对象是否是某个类(构造函数)的实例,或者是否继承自某个类。
  • 替代 constructor 属性: 虽然可以通过 对象.constructor 获取构造函数,但这属性可以被修改,不如 instanceof 基于原型链的检测可靠。

3. API 与用法 (API & Usage)

instanceof 运算符的语法如下:

javascript
object instanceof constructor
  • object: 要检测的对象。
  • constructor: 用于检测的构造函数。

它返回一个布尔值:true 表示 objectconstructor 的实例(或继承自 constructor),false 则表示不是。

核心原理描述:

instanceof 的检测过程是一个循环遍历过程。它会沿着 object 的原型链向上查找,从 object.__proto__ 开始,然后是 object.__proto__.__proto__,以此类推,直到原型链的顶端(null)。在查找过程中,如果找到任何一个原型对象与 constructor.prototype 严格相等 (===),则返回 true。如果遍历到原型链的末端仍未找到,则返回 false

代码示例 (摘自 MDN / 核心原理模拟):

javascript
// 官方解释辅助理解
// (object instanceof constructor) 大致等价于以下过程
// 伪代码实现:
// function instanceof(object, constructor) {
//   let proto = object.__proto__; // 获取对象的原型
//   while (true) {
//     if (proto === null) { // 遍历到原型链顶端
//       return false;
//     }
//     if (proto === constructor.prototype) { // 找到匹配的原型
//       return true;
//     }
//     proto = proto.__proto__; // 继续向上查找原型链
//   }
// }

// 经典示例
function Animal(name) {
  this.name = name;
}

function Dog(name) {
  Animal.call(this, name); // 继承属性
}

// 建立原型链继承关系
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // 恢复 constructor 属性

const myDog = new Dog("Buddy");
const myAnimal = new Animal("Generic");
const str = "hello";

console.log(myDog instanceof Dog);       // true
console.log(myDog instanceof Animal);    // true (因为 Dog 的原型链上包含 Animal.prototype)
console.log(myDog instanceof Object);    // true (因为原型链最终指向 Object.prototype)
console.log(str instanceof String);      // false (str 是原始类型,非 String 对象实例)
console.log(new String("hello") instanceof String); // true (这是 String 对象)
console.log([] instanceof Array);        // true
console.log([] instanceof Object);       // true
console.log(null instanceof Object);     // false (null 没有原型链)
console.log(undefined instanceof Object);// false (undefined 没有原型链)

注意:上面的伪代码 instanceof(object, constructor) 仅用于解释其原理,实际的 instanceof 运算符是引擎内置的,并非函数。__proto__ 属性在标准中已被 Object.getPrototypeOf() 替代使用。

4. 关键注意事项 (Key Considerations)

  • 基于原型链: instanceof 完全依赖于原型链的结构。如果原型链被人为修改,结果可能会不符合预期。
  • 不能检测原始类型: instanceof 只能用于检测对象类型,对原始类型(如 string, number, boolean, null, undefined, symbol, bigint)使用 instanceof 总是返回 false(除了包装对象如 new String() 的情况)。
  • 跨 Realm/iframe 问题: 在不同的 JavaScript 运行时环境(如不同的 iframe 或 Web Worker)之间传递对象,它们的全局对象和内置构造函数可能不同,导致 instanceof 检测失败,即使它们是同一种类型。这时通常需要使用 Object.prototype.toString.call(obj) 来获取更准确的类型字符串。
  • Symbol.hasInstance: 从 ES6 开始,可以通过给构造函数添加 Symbol.hasInstance 静态方法来定制 instanceof 的行为。这允许开发者自定义对象和构造函数之间的关系判断逻辑。

5. 参考资料 (References)

不知道说啥了很无语了