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

栏目: JavaScript · 发布时间: 5年前

内容简介:在面向对象语言中,一般都有关键字 instanceof 来检测对象类型,更准确点来说是检测对象是哪个类型的实例。那么在 JS 中这个关键字又有什么不同之处呢?此文仅是一篇对 ES 标准中 instanceof 关键字的解读,并记录了在此过程中的对 JS 中对象系统的一点小感悟。先举例 a instanceof b, 下文中的步骤解释中关键字左侧的值用a表示, 右侧的值用b表示。在标准中 instanceof 的行为被抽象到 InstanceofOperator 操作中,下面列出比较关键的两个抽象操作,并根据

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

标准规定该关键字需要做什么

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

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

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

InstanceofOperator ( a, b)

  1. 检测b是否是对象,否TypeError
  2. 获取b是否定义了Symbol.hasInstance
  3. 是则bSymbol.hasInstance,返回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不是对象是什么情况

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

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

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

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

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

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

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

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

这一步存疑的原因是,没有直接理解标准中的描述,只是有所猜测,不能确定,故验证之。

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
复制代码

代码传送门

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

一点思考

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

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

结论

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


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

无界

无界

(美)艾米莉·内格尔·格林(Emily Nagle Green) / 卞斌 / 机械工业出版社 / 2011-5 / 39.00元

"数十亿人身在其中、数十万亿美元的新生意,你我此生最大的科技革命,这次转型将如何改变我们的生活? 又如何使我们做生意的方式起革命性的变化? 无界会比你所想更快降临,将创造数兆美元的新价值。你的行动够快吗?这本放眼未来的著作,结合专家的洞见、战术性工具,以及扬基集团独有的无界趋势数据,提供你需要的一切。" 未来的世界和企业,会走向无界的状态,也就是人、构想和产品经由一张全球性的数字......一起来看看 《无界》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

SHA 加密
SHA 加密

SHA 加密工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具