JS-手写instanceof

96 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第15天,点击查看活动详情

前言

JS 中自带的 instanceof 方法,可以判断出右侧构造函数prototype,是否位于左侧对象原型链上。

本文通过手写实现 instanceof,了解其使用和原理。

代码

首先,还是先定义对应函数,确定参数和返回值。

参数可以确定至少有两个,一个是被查询的对象,一个是对应的构造函数;返回值应该是 boolean 类型,默认返回 false,所以代码如下:

/**
 * 实现 instanceof
 * @param { any } instance 构造实例
 * @param { Object } builder 目标构造函数
 * @returns { boolean }
 */
function myInstanceof (instance, builder) {
  return false
}

需要注意的是,JSinstanceof 左侧可以是任何类型的值,但如果不是 Object 对象,就直接返回 fasle,如下:

微信截图_20221021162453.png

但是,如果这个基本类型的变量是通过 new 生成的,却可以使用 instanceof 进行判断:

微信截图_20221021162712.png

因为通过 new 创建的,都是一个对象,符合 instanceof 的规则:

微信截图_20221021162744.png

所以,手写的 myInstanceof 的第一步就是对参数进行检测,如果不符合要求,返回 false,代码如下:

function myInstanceof (instance, builder) {
  // 这种写法,排除 instance 是 null 和 undefined
  let __proto__ = instance && instance.__proto__
  const builderPrototype = builder && builder.prototype
  // 类型检测
  // 如果 `instance` 不是 `Object` 类型,返回 false
  // 判断 `instance` 上不存在原型链,或者 `builder` 上不存在 `prototype`,返回 false
  if (typeof instance !== 'object' || !builderPrototype || !__proto__) {
    return false
  }
  return false
}

然后就是判断 builderPrototype 是否存在于 instance 的原型链上,因为不知道原型链上共有多少层,所以,基本需要递归或者循环来进行逐层判断,直到原型链到尽头或者原型链上的某一层就是 builderPrototype,代码如下;

function myInstanceof (instance, builder) {
  // 类型检测
  let __proto__ = instance && instance.__proto__
  const builderPrototype = builder && builder.prototype
  if (typeof instance !== 'object' || !builderPrototype || !__proto__) {
    return false
  }

  // 循环检测,直到原型链为 null
  while (__proto__) {
    // 如果找到,返回 true,结束循环
    if (__proto__ === builderPrototype) {
      return true
    }
    // 逐层读取原型链
    __proto__ = __proto__.__proto__
  }

  // 循环结束,表明没有找到,返回 false
  return false
}

至此,一个基本的 myInstanceof 就实现了,测试一把:

console.log('my instanceof 1:', myInstanceof(1, Number))
console.log('my instanceof 2:', myInstanceof(new String('abc'), String))
console.log('my instanceof 3:', myInstanceof(person, Person))

微信截图_20221021164153.png