手写实现 instanceof 运算符

理解 JavaScript 原型链,手动实现 instanceof 运算符的逻辑

问题

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。我们需要手动实现这个运算符的功能,以加深对 JavaScript 原型链机制的理解。

解答

/**
 * 手写实现 instanceof 运算符
 * @param {Object} obj - 需要检测的实例对象
 * @param {Function} constructor - 构造函数
 * @returns {Boolean} - 如果 obj 是 constructor 的实例则返回 true,否则返回 false
 */
function myInstanceOf(obj, constructor) {
  // 基本类型直接返回 false
  if (obj === null || typeof obj !== 'object' && typeof obj !== 'function') {
    return false;
  }
  
  // 构造函数必须是函数类型
  if (typeof constructor !== 'function') {
    throw new TypeError('Right-hand side of instanceof is not callable');
  }
  
  // 获取构造函数的 prototype
  const prototype = constructor.prototype;
  
  // 获取对象的原型
  let proto = Object.getPrototypeOf(obj);
  
  // 沿着原型链查找
  while (proto !== null) {
    // 找到相同的原型,返回 true
    if (proto === prototype) {
      return true;
    }
    // 继续向上查找
    proto = Object.getPrototypeOf(proto);
  }
  
  // 遍历完原型链都没找到,返回 false
  return false;
}

使用示例

// 示例 1: 基本使用
function Person(name) {
  this.name = name;
}

const person = new Person('张三');
console.log(myInstanceOf(person, Person)); // true
console.log(myInstanceOf(person, Object)); // true
console.log(myInstanceOf(person, Array));  // false

// 示例 2: 数组检测
const arr = [1, 2, 3];
console.log(myInstanceOf(arr, Array));   // true
console.log(myInstanceOf(arr, Object));  // true

// 示例 3: 基本类型
console.log(myInstanceOf(123, Number));     // false
console.log(myInstanceOf('hello', String)); // false
console.log(myInstanceOf(null, Object));    // false

// 示例 4: 包装对象
const num = new Number(123);
console.log(myInstanceOf(num, Number));  // true
console.log(myInstanceOf(num, Object));  // true

// 示例 5: 继承关系
class Animal {}
class Dog extends Animal {}
const dog = new Dog();
console.log(myInstanceOf(dog, Dog));     // true
console.log(myInstanceOf(dog, Animal));  // true
console.log(myInstanceOf(dog, Object));  // true

// 示例 6: 自定义原型链
function Parent() {}
function Child() {}
Child.prototype = new Parent();
const child = new Child();
console.log(myInstanceOf(child, Child));  // true
console.log(myInstanceOf(child, Parent)); // true

关键点

  • 原型链遍历:通过 Object.getPrototypeOf() 方法不断获取对象的原型,沿着原型链向上查找

  • 边界条件处理

    • 基本类型(null、undefined、number、string、boolean)直接返回 false
    • 构造函数必须是函数类型,否则抛出类型错误
  • 终止条件

    • 找到匹配的 prototype 时返回 true
    • 原型链遍历到顶端(null)时返回 false
  • 与原生 instanceof 的区别:原生 instanceof 是运算符,性能更优;手写版本主要用于理解原型链机制

  • 原理:instanceof 的本质是检查 constructor.prototype 是否在 obj 的原型链上,这体现了 JavaScript 基于原型的继承机制