你真的了解 instanceof 吗?

1,800 阅读3分钟
原文链接: github.com

通常解释

在JS中,用typeof来判断基本类型,instanceof判断引用类型
这是大家通常的解释

但是,你真的了解instanceof吗?

例子

先看几个例子热一下身

console.log('aa' instanceof String) // 都说了判断引用类型,拿个基本类型出来坑爹么
let obj_string = new String('aa');
console.log(obj_string instanceof String)
// 大家伙们都属于object
console.log({} instanceof Object)
console.log([] instanceof Array)
console.log([] instanceof Object)
console.log(function() {} instanceof Function)
console.log(function() {} instanceof Object)
function Foo(){} 
function BFoo(){} 
Foo.prototype = new BFoo();//JavaScript 原型继承
let foo = new Foo();
console.log(foo instanceof Foo);
console.log(foo instanceof BFoo);

其实上面三个例子都比较基础,相信都难不倒大家,再看几个复杂点的

console.log(String instanceof String); 
console.log(Object instanceof Object); 
console.log(Function instanceof Function); 
console.log(Function instanceof Object);

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

打印看看,你全答对了吗?
是的话就不用看下去了,大神请回吧;
如果不是,那可以往下翻一翻

MDN的定义

instanceof - JavaScript | MDN

object instanceof constructor

instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。

先看MDN里面的解释,左边是要测试的对象,右边是构造函数 是否能在对象的原型链上(顺着__proto__一直往上找)找到构造函数的原型属性([constructor].prototype)

直接看实现代码吧

function instance_of(L, R) {//L 表示左边的object,R 表示右边的constructor
 const R_P = R.prototype;// 取 R 的显式原型
 L = L.__proto__;// 取 L 的隐式原型,并且可能会顺着原型链重新赋值
 while (true) { 
   if (L === null) 
     return false; 
   if (R_P === L)// 这里重点:严格比较 true 
     return true; 
   L = L.__proto__; 
 } 
}

再祭出我们的原型链大杀器
image

划个重点

  1. __proto__属性,指向了创建该对象的构造函数的原型
  2. 所有JS 对象都有 __proto__ 属性,除了Object.prototype.__proto__ === null
  3. 注意Object(),它是由function生成的,所以它的__proto__属性指向了function的构造器Function的原型Function.prototype
  4. 注意构造器Function,它是唯一一个prototype__proto__指向相同的对象
  5. 一般来说,我们日常自行创建的构造器Foo__proto__属性指向function的构造器Function的原型Function.prototype,但是构造器的原型对象Foo.prototype__proto__属性是直接指向Object.prototype对象的

例子讲解:彻底捋清instanceof

直接找一个例子来讲解,相信聪明的你们一定能够融会贯通,举一反三

console.log(Object instanceof Object); // true

再看instanceof的实现代码

function instance_of(L, R) {//L 表示左边的object,R 表示右边的constructor
 const R_P = R.prototype;// 取 R 的显式原型
 L = L.__proto__;// 取 L 的隐式原型,并且可能会顺着原型链重新赋值
 while (true) { 
   if (L === null) 
     return false; 
   if (R_P === L)// 这里重点:严格比较 true 
     return true; 
   L = L.__proto__; 
 } 
}

1、第一轮赋值

首先,左右表达式赋值

L = Object
R = Object
R_P = Object.prototype = Object.prototype
L = Object.__proto__ = Function.prototype

2、第一次判断

L !== null => R_P !== L
判断不为true
继续寻找L的原型链,准备下一轮赋值

3、第二轮赋值

L = Function.prototype.__proto__  =  Object.prototype

4、第二次判断

L !== null => R_P === L

return true

完美结束!

好了,其他的例子,请同学们自己去分析吧,你现在可以出去跟别人说:我真滴了解instanceof!