浅谈 instanceof 原理

635 阅读1分钟

在 JavaScript 中,我们通常用 typeof 来判断基本类型,用 instanceof 来判断引用类型,虽然判断引用类型还有更好的方式,我们等会再来说说。那么,instanceof 是什么呢?

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

根据上述概念我们来实现 instanceof 的源码

function myInstanceof(instanceObj, constructorFun) {
  const prototypeObj = constructorFun.prototype // 获取构造函数的原型对象
  instanceObj = instanceObj.__proto__ // 获取实例对象的原型
  while (instanceObj) {
    if (prototypeObj === instanceObj) {
      return true
    }
    instanceObj = instanceObj.__proto__ // 层层向上遍历
  }
  return false
}

// test
console.log(myInstanceof(Function, Function))
console.log(Function instanceof Function)

接下来我们来看几个比较复杂的例子

console.log(String instanceof String);  // false
console.log(String instanceof Object);  // true
console.log(Object instanceof Object);  // true
console.log(Function instanceof Function);  // true
console.log(Function instanceof Object); // true

function Foo(){} 
function BFoo(){} 
Foo.prototype = new BFoo();
console.log(Foo instanceof Function); // true
console.log(Foo instanceof Foo); // false

注意构造器 Function ,它是唯一一个 prototype 和 __proto__ 指向相同的对象。

注意 Object() ,它是由 function 生成的,所以它的 __proto__ 属性指向了 function 的构造器 Function 的原型 Function.prototype。

把上述例子代入 myInstanceof() 方法,逐条分析~

console.log(Function instanceof Function);  // true
STEP1
L = Function.prototype
R = Function.__proto__
// 造器 Function ,它是唯一一个 prototype 和  __proto__ 指向相同的对象
L === R // true

再看一条

console.log(Object instanceof Object);  // true
STEP1
L = Object.prototype
R = Object.__proto__  = Function.prototype
L !== R // 继续下一步
STEP2
L = Object.prototype
R = Function.prototype.__proto__  = Object.prototype
L === R  // true

判断引用类型更好的方式

let arr = [1, 2]
console.log(Object.prototype.toString.call(arr) === '[object Array]') // true
console.log(arr instanceof Array) // true
console.log(arr instanceof Object) // true

因为原型链继承的关系,instanceof 会把数组都识别为 Object 对象。所以用 Object.prototype.toString.call(xxx) 方法会更准确一点。