Javascript:手写instanceof

131 阅读1分钟

作用

用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上。

instanceof缺点

  1. 不考虑当前实例对象是否是该构造函数的实例对象,只要能在当前实例对象的原型链上找到该结构函数的原型对象,就会返回true
  2. 实例对象的原型链被改写时,使用instanceof判断对象是否是构造函数的实例对象时也会返回true

看以下代码:

function Person(name, age) {
  this.name = name;
  this.age = age;
}

const person = new Person('cc', 21);
console.log(person instanceof Person);  // true

此时person.__proto__ === Person.prototype,打印结果为true

const obj = {};
obj.__proto__ = Person.prototype;
console.log(obj instanceof Person);  // true

此时obj__proto__被设置为构造函数Person的原型对象,即原型链被改写,打印结果为true

手写instanceof

function _instanceof(left, right) {
  if (!left || !right) return;
  if (typeof left !== 'object') {
    throw Error('参数1非对象');
  }
  if (typeof right !== 'function') {
    throw Error('参数2非构造函数');
  }
  
  // 获取左侧对象的原型
  const proto = Object.getPrototypeOf(left);
  // 循环获取右侧原型,找到了就终止循环
  while(proto !== right.prototype) {
    // 找不到原型返回false
    if (proto === null) return false;
    // 沿原型链获取原型
    proto = Object.getPrototypeOf(proto);
  }

  return true;
}

Object.getPrototypeOf是 Object 提供的获取对象原型的方法;
object.__proto__,是手动去访问对象的原型。
两者作用相同,即Object.getPrototypeOf(proto) = proto.__proto__。因此,可以使用以下写法:

function _instanceof(left, right) {
  // 边界值判断
  
  // 替换为object.__proto__
  const proto = left.__proto__;
  while(proto !== right.prototype) {
    if (proto === null) return false;
    proto = proto.__proto__;
  }

  return true;
}