实现 instanceOf 操作符

基础知识

instanceof 操作符用于检测一个构造函数的 prototype 属性,是否存在于一个指定对象的原型链上。这是 JavaScript 中判断对象类型、实现继承等场景下的核心工具。要实现它,我们必须理解 JavaScript 的原型机制。

  1. 原型 (Prototype): 在 JavaScript 中,对象可以从其他对象继承属性。这个“其他对象”就是所谓的“原型”。每个对象都有一个指向其原型的内部链接。

  2. Object.getPrototypeOf(obj): 这是 ES5 提供的标准方法,用于获取一个对象(obj)的原型。在一些旧的实现或调试中,你可能也会看到非标准的 __proto__ 属性。

  3. 构造函数的 prototype 属性: 每个函数在创建时,都会被自动赋予一个 prototype 属性。这个属性的值是一个对象,我们称之为“原型对象”。当使用 new 关键字调用该函数创建实例时,新实例的原型就会指向这个“原型对象”。

  4. 原型链 (Prototype Chain): 实例的原型指向构造函数的原型对象,而原型对象本身也是一个对象,它也有自己的原型,这样一层层向上追溯,直到某个对象的原型为 null(原型链的终点),就形成了一条“原型链”。

obj instanceof Constructor 的本质,就是在 obj 的整条原型链上,寻找是否存在 Constructor.prototype 这个对象。

核心思路

我们的目标是创建一个函数 myInstanceof(left, right),模拟原生 instanceof 的行为。核心思路可以概括为“顺藤摸瓜”

  1. 首先,拿到“瓜”,也就是 right (构造函数) 的原型对象 right.prototype。这是我们要寻找的目标。
  2. 然后,拿到“藤”的起点,也就是 left (实例对象) 的原型 Object.getPrototypeOf(left)
  3. 顺着“藤”一直向上爬(遍历原型链),在每一节都检查一下,看看手里的“藤”是不是我们要找的那个“瓜”。
  4. 如果爬到一半找到了,那就说明“瓜熟蒂落”,leftright 的实例,返回 true
  5. 如果一直爬到藤的尽头(原型为 null),都还没找到,那就说明它们没关系,返回 false

代码实现

下面是 myInstanceof 的一个完整实现。

/**
 * 自定义 instanceof 操作符
 * @param {any} left - 要检查的实例对象
 * @param {Function} right - 构造函数
 * @returns {boolean} - 如果 left 是 right 的实例,则返回 true,否则返回 false。
 */
function myInstanceof(left, right) {
  // 1. 校验右侧参数必须是一个函数
  if (typeof right !== 'function') {
    throw new TypeError('Right-hand side of "instanceof" is not a function');
  }

  // 2. 校验左侧参数必须是对象(或函数),原始值没有原型链
  if (
    left === null ||
    (typeof left !== 'object' && typeof left !== 'function')
  ) {
    return false;
  }

  // 3. 获取要寻找的目标:构造函数的原型对象
  const targetPrototype = right.prototype;

  // 4. 获取实例对象的原型,作为遍历的起点
  let proto = Object.getPrototypeOf(left);

  // 5. 开始循环,沿着原型链向上查找
  while (proto) {
    // 检查当前原型是否就是目标原型
    if (proto === targetPrototype) {
      return true;
    }
    // 如果不是,则将指针移到原型链的上一环
    proto = Object.getPrototypeOf(proto);
  }

  // 6. 如果循环结束,说明已到原型链顶端,仍未找到
  return false;
}

代码解析

  1. 参数校验:首先对 rightleft 进行校验。
    • instanceof 的右边必须是函数,因为它需要访问 .prototype 属性。
    • 左边必须是对象类型(函数也是对象),因为原始值(如 1, 'a', true)没有原型链,直接判断为 false 即可。
  2. 获取目标与起点
    • targetPrototype 是我们要在原型链上寻找的终点。
    • proto 是我们开始查找的起点,即实例 left 的直接原型。
  3. 循环遍历(while (proto)):启动一个 while 循环,条件是 proto 必须是一个真值(不能是 null)。因为原型链的终点是 null,所以当 proto 变为 null 时,循环会自动停止,代表已经搜完了整条链。
  4. 比较与上溯
    • if (proto === targetPrototype):在循环的每一步,都将当前的原型 proto 与我们的目标 targetPrototype 进行严格比较。如果相等,证明目标已找到,函数立即返回 true
    • proto = Object.getPrototypeOf(proto);:如果不相等,就通过 Object.getPrototypeOf(proto) 获取当前原型的原型,相当于在链条上向后移动一步,准备进行下一次循环比较。
  5. 返回结果:如果 while 循环因为 proto 变为 null 而自然结束,代码会执行到循环体之外。这说明整条原型链都被搜索过了,但没有找到目标,因此函数返回 false
Copyright © Jun 2025 all right reserved,powered by Gitbook该文件修订时间: 2025-07-03 17:35:08

results matching ""

    No results matching ""

    results matching ""

      No results matching ""