instanceof使用中可能漏掉的一点细节

前言

在面向对象语言中,通常都有关键字 instanceof 来检测对象类型,更准确点来讲是检测对象是哪一个类型的实例。那么在 JS 中这个关键字又有什么不一样之处呢?此文仅是一篇对 ES 标准中 instanceof 关键字的解读,并记录了在此过程当中的对 JS 中对象系统的一点小感悟。javascript

标准规定该关键字须要作什么

先举例 a instanceof b, 下文中的步骤解释中关键字左侧的值用a表示, 右侧的值用b表示。java

在标准中 instanceof 的行为被抽象到 InstanceofOperator 操做中,下面列出比较关键的两个抽象操做,并根据本身的理解对整理了下步骤:编程

  • InstanceofOperator ( a, b);
  • OrdinaryHasInstance ( b, a );

InstanceofOperator ( a, b)

  1. 检测b是不是对象,否TypeError
  2. 获取b是否认义了Symbol.hasInstance
  3. 是则b[Symbol.hasInstance](a),返回true或false
  4. 不然判断b是不是函数,不然TypeError
  5. 是则返回OrdinaryHasInstance(b, a)的运行结果

OrdinaryHasInstance ( b, a )

  1. 判断b是不是函数,不然返回false(这一步在这一场景中应该不会被调用)
  2. 是则判断b是不是被bind包装过的函数,是则获取到bind包装的函数bc,并调用InstanceofOperator( a, bc)
  3. 是则检测a是不是对象,不然返回false
  4. 是则获取b的prototype属性bp
  5. 若是bp不是对象则返回TypeError
  6. 获取a的原型并赋值给a
  7. 检测a是否为null,是则返回false
  8. 不然判断a和bp是否相等,是则返回true
  9. 不然重复步骤11~14直至返回true或false

几处细节的推敲

在查看标准解释是,有几处理解的不是很明白,故使用几个demo对本身的理解作了验证函数

b应该是什么值

先看b不是对象是什么状况 ui

从上面的结果能够看到报错了,并且错误提示很明显的提示右侧的值不是对象,这是第1步检测报的错,那么若是是对象,而不是函数对象又会是什么状况呢?this

嗯,没错,对象也报错了,此次的错误是右侧的值不可调用,即不是函数,这应是第4步检测报的错了。根据上面的步骤试试给对象设置Symbol.hasInstance属性spa

这一次没有报错,检测正常进行了,且返回了在函数中定义的结果,根据上面的步骤和代码验证,能够得出右侧的值能够是设置了Symbol.hasInstance属性的对象。且检测的结果会被右侧值定义的Symbol.hasInsyance函数拦截成函数返回的结果。

右侧是函数的状况就是比觉正常的返回了,须要明确的一点是函数是不能直接设置Symbol.hasInstance属性的,具体缘由,感兴趣的能够继续查阅资料。到这里能够得出结论,b必须是设置了Symbol的对象或者函数,不然会报错。prototype

被 dind 包装过的函数依然会返回原函数原型检测结果

这一步存疑的缘由是,没有直接理解标准中的描述,只是有所猜想,不能肯定,故验证之。code

var a = function() {
   this.name = 'a';
}; 
var b = {testName: 'b'};
a.prototype = b;

var c = new a();
console.log('c instanceof a', c instanceof a);   // true

var h = {name: 'h'};
var s = a.bind(h);
console.log('c instanceof s', c instanceof s);   // true
复制代码

代码传送门cdn

如上代码示例,从其运行结果可知,a.prototype 是等于 c 的原型的,s 是 a 被 bind 对象 h 后返回的函数,从验证结果来看,函数通过 bind 的一层包装,依然不会影响其原型检测的绑定。

一点思考

在推敲上面细节时忽然联想到这种检测实际是很合理的,类比 Java 中的检测类,这里对象的原型不就能够类比成 Java 里面的类么。 某个对象的原型是什么决定它具有了原型对象的特性的,而类不也是这样么,该对象属于哪一个类,决定了该对象具有了哪些特性。不一样的是,在JS中的检测是往继承链上多退了一步的,Java 中是直接检测对象是不是该类的实例,而JS中是检测的是对象的原型是否等于函数的prototype属性,这应该就是继承原理不一样产生的区别吧。

以前从未认真的思考过,JS 中的整个对象系统是什么样的,虽然如今也仍是没有理解太多,可是至少如今在个人认知里 JS 的 对象系统是简单而完善的,并无由于简单而缺乏了面向对象基本特性。虽然它灵活的容许你随便更改一个对象的原型,也就是类,可是这依然不妨碍它成为一门能够面像对象编程的语言。

结论

instanceof 关键字检测的本质是检测左侧对象的原型链上是否存在和右侧函数的prototype属性相等的对象,若是存在则返回true,若是不存在则返回false。

相关文章
相关标签/搜索