资讯专栏INFORMATION COLUMN

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

lauren_liuling / 774人阅读

摘要:代码传送门如上代码示例,从其运行结果可知,是等于的原型的,是被对象后返回的函数,从验证结果来看,函数经过的一层包装,依然不会影响其原型检测的绑定。

前言

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

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

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

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

InstanceofOperator ( a, b);

OrdinaryHasInstance ( b, a );

InstanceofOperator ( a, b)

    检测b是否是对象,否TypeError

    获取b是否定义了Symbol.hasInstance

    是则bSymbol.hasInstance,返回true或false

    否则判断b是否是函数,否则TypeError

    是则返回OrdinaryHasInstance(b, a)的运行结果

OrdinaryHasInstance ( b, a )

    判断b是否是函数,否则返回false(这一步在这一场景中应该不会被调用)

    是则判断b是否是被bind包装过的函数,是则获取到bind包装的函数bc,并调用InstanceofOperator( a, bc)

    是则检测a是否是对象,否则返回false

    是则获取b的prototype属性bp

    如果bp不是对象则返回TypeError

    获取a的原型并赋值给a

    检测a是否为null,是则返回false

    否则判断a和bp是否相等,是则返回true

    否则重复步骤11~14直至返回true或false

几处细节的推敲

在查看标准解释是,有几处理解的不是很明白,故使用几个demo对自己的理解做了验证

b应该是什么值

先看b不是对象是什么情况

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

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

这一次没有报错,检测正常进行了,且返回了在函数中定义的结果,根据上面的步骤和代码验证,可以得出右侧的值可以是设置了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。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/6703.html

相关文章

  • Javascript模式 阅读笔记-1.函数模式

    摘要:模式阅读笔记第一部分函数模式总的来说模式是一本力荐的进阶书书里面涉及了很多在学习过程中会碰到的坑然后提供了很不错的解决方法虽然很多人吐槽这本书的翻译但是糟糕的翻译还是无法掩盖这是一本好书的事实因此这里我会结合书上的知识和我的理解来写一些 Javascript模式 阅读笔记-第一部分-函数模式 总的来说,javascript模式是一本力荐的js进阶书,书里面涉及了很多在学习javascr...

    PiscesYE 评论0 收藏0
  • 关于如何把项目做得更好的一次思考

    摘要:怎么样才能把项目做的好一点或者更好首先,在老板看来,他肯定希望今天提的需求可以立马就上线。关于注释注释是有必要的,这个对个人和他人都是有好处的。 之前做开发的时候对项目完全没有一个整体的思考,需求来了就知道做,只关心自己做的那部分的功能,做完拉到。但最近所做的项目中,遇到了不少问题,自己都忍不住吐槽起来了。如:项目经常性延期、代码冗余、添加一个很小的新功能都需要改动很多地方,还对之前的...

    罗志环 评论0 收藏0
  • 关于如何把项目做得更好的一次思考

    摘要:怎么样才能把项目做的好一点或者更好首先,在老板看来,他肯定希望今天提的需求可以立马就上线。关于注释注释是有必要的,这个对个人和他人都是有好处的。 之前做开发的时候对项目完全没有一个整体的思考,需求来了就知道做,只关心自己做的那部分的功能,做完拉到。但最近所做的项目中,遇到了不少问题,自己都忍不住吐槽起来了。如:项目经常性延期、代码冗余、添加一个很小的新功能都需要改动很多地方,还对之前的...

    Enlightenment 评论0 收藏0
  • 代码自动生成在重构的一次探索

    摘要:事件只能携带一个的。例如在上述代码示例中的将所有使用发布事件的地方,全部修改为使用的方法。是否能够编写脚本或者自动化工具,自动化的完成重构工作。实施方案使用注解解析自动生成文件我们都知道,是通过注解来实现的。 欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 作者:吴涛 导语:EventBus 已经火了很长一段时间了。最近我们项目决定引入EventBus,替换我们播放器现在的事...

    ztyzz 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<