JS 手写: instanceof

2023-05-17 15:16:19 浏览数 (2)

# 介绍

# Try it

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

代码语言:javascript复制
function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}
const auto = new Car('Honda', 'Accord', 1998);

console.log(auto instanceof Car);
// expected output: true

console.log(auto instanceof Object);
// expected output: true

# 语法

object instanceof constructor

  • 参数 object 某个实例对象 constructor 某个构造函数
  • 描述 instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。
代码语言:javascript复制
// 定义构造函数
function C() {}
function D() {}

var o = new C();

o instanceof C; // true, 因为 Object.getPrototypeOf(o) === C.prototype

o instanceof D; // false, 因为 D.prototype 不存在于 o 的原型链上

o instanceof Object; // true, 因为 Object.prototype.isPrototypeOf(o) === true
C.prototype instanceof Object // true,同上

C.prototype = {};
var o2 = new C();

o2 instanceof C; // true

o instanceof C; // false , 因为 C.prototype 指向了一个空对象,这个对象不在 o 的原型链上

D.prototype = new C(); // 继承
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true

需要注意的是,如果表达式 obj instanceof Foo 返回 true,则并不意味着该表达式会永远返回 true,因为 Foo.prototype 属性的值有可能会改变。另外一种情况下,原表达式的值也会改变,就是改变对象 obj 的原型链的情况,虽然在目前的 ES 规范中,我们只能读取对象的原型而不能改变它,但借助于非标准的 __proto__ 伪属性,是可以实现的。

# 应用

检测对象是不是某个构造函数的实例

代码语言:javascript复制
if (!(mycar instanceof Car)) {
  throw new Error('mycar is not an instance of Car');
}

# 实现

# 思路

  • 拿到当前类的原型,拿到实例对象的原型链
  • 沿着实例对象原型链,查找是否存在类的原型,直到尽头
    • 获取当前实例对象的原型,沿着原型链一直往上找
    • 如果在原型链上找到了类的原型,则返回 true
    • 如果直到 Object 的基类 null 都没有找到,则返回 false

# 代码

代码语言:javascript复制
function myInstanceof (obj, constructor) {
  let proto = Object.getPrototypeOf(obj); // 实例对象的原型
  while (true) {
    if (proto === null) { // 到达尽头
      return false;
    }
    if (proto === constructor.prototype) { // 找到了
      return true;
    }
    proto = Object.getPrototypeOf(proto); // 沿着原型链继续找
  }
}

这里的 Object.getPrototypeOf(obj) 可以使用 obj.__proto__ 代替。但是推荐使用 Object.getPrototypeOf(obj),因为 __proto__ 已经被弃用了。

0 人点赞