最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 【译】对象加数组不等于0(含自己总结)

    正文概述 掘金(Heiton)   2021-03-20   528

    你可能看过Gary Bernhardt的 WAT的演讲,他在其中谈到了这些令人困惑的JavaScript代码:

    {} + []  // 0
    [] + {} // "[object Object]" 【译者注:Object.prototype.toString.call({})的结果是"[object Object]"】
    [] + [] // "" 【译者注】
    {} + {} // "[object Object][object Object]"  【译者注】
    

    他向观众展示了一个对象和一个数组相加结果是0,但是一个数组和一个对象相加结果是"[object Object]"。瞧,如果您在chrome控制台中尝试此操作,那么您将获得:

    【译】对象加数组不等于0(含自己总结)

    但是,如果将这些行用括号括起来,则可以看到这两行的计算结果相同:

    【译】对象加数组不等于0(含自己总结)

    发生什么了?让我们看一下抽象语法树,看看语法上是否有奇怪的事情发生。

    如果我们将{} + []插入ASTExplorer,得到这个:

    【译】对象加数组不等于0(含自己总结)

    一个空对象后面跟着一个一元+操作符?那不是对象加数组!那是……完全不同的东西。

    为了证实我们的怀疑,我们看到Javascript的作用于数组的一元+运算符的值为0,表明我们的解释确实正确。空代码块被评估为noop,剩下的就是一元表达式:

    【译】对象加数组不等于0(含自己总结)

    我们再去ASTExplorer 以确保[] + {}实际上像我们期望的那样向对象添加了一个数组:

    【译】对象加数组不等于0(含自己总结)

    是的!我们的理解在这里看起来不错!因此,如果我们对语法感到困惑,请将其插入ASTExplorer,然后一切都会显示出来,对吗?

    但是故事还没结束。还记得我们如何将某些内容粘贴到ASTExplorer中以查看其解析,然后将其粘贴到Chrome控制台中以查看其行为吗?让我们使用常规的JavaScript对象尝试相同的过程。 Chrome会执行我们期望的操作并创建一个对象:

    【译】对象加数组不等于0(含自己总结)

    但是,当将其粘贴到ASTExplorer中时,将得到以下内容:

    【译】对象加数组不等于0(含自己总结)

    什么?为什么ASTExplorer认为这是语法错误?我们正在声明一个对象!这就像JavaScript的第一天! ASTExplorer怎能不赶上呢? 事实证明ASTExplorer实际上就在这里,而Chrome正是其中一种怪异的表现。任何其他语句之外的裸对象都不会被解析为裸对象,而是被解析为一个代码块,就像之前一样!由于代码块的内部内容不作为语句进行解析,因此解析失败,从而导致冒号上的语法错误。 通过eval可以确信这是对的:

    【译】对象加数组不等于0(含自己总结)

    当Chrome控制台出现明显的语法错误时,为什么最终会创建对象? Chrome之所以这样做,是因为当您将某些内容粘贴到Chrome控制台中时,您本能地拥有两种不同的行为期望:

    1. Chrome控制台会计算语句。
    2. 将表达式粘贴到Chrome控制台中应计算该表达式。

    这两个期望从根本上彼此冲突,并且无法调和。它们导致了如何解析裸对象的根本矛盾。 为了弥补这一差距,Chrome浏览器会动态找出是将行解析为“语句”还是“表达式”。作为表达式,该行最终求值到一个对象,但是作为语句,该行最终出现语法错误。 Chrome改变了他们在此处使用的确切规则,但是他们遵循的规则似乎是这种行为:

    1. 查看输入是否以{开头并以}结尾
    2. 如果不是,则将输入解析为一系列语句(statement)
    3. 如果是,则将输入解析为表达式(expression)
    4. 如果失败,则回过头来将输入解析为一系列语句

    我大约有90%的把握就是今天的样子,但是我也没有像一年前那样检查,而且我也不会深入研究Chrome源码来再次解决问题。

    总结下:

    • 对象加数组不是0,及时在Chrome控制台看起来是0
    • 如果对语法感到疑惑,使用ASTExplorer
    • Chrome控制台是计算语句和表达式的好方法,但是...
    • Chrome控制台有一些狭窄的陷阱
    • 如果你还是感到困惑,eval可以告诉你真相的来源

    译者总结的相关"八股文"及其相关理解:

    加法会进行隐式转换,规则是调用其 valueOf() 或 toString() 以取得一个原始值。如果两个值中的任何一个是字符串,则进行字符串拼接,否则进行数字加法。

    [] 和 {} 的 valueOf() 都返回对象自身,所以都会调用 toString()。

    [].toString() 返回空字符串,({}).toString() 返回“[object Object]”。

    +[] // 0 【对一个空数组执行正号运算,实际上就是把数组转型为数字。先调用 [].valueOf()返回自身,继续调用[].toString(),返回空字符串。空字符串转型为数字0】
    +{} // NaN
    [].toString() // ""
    {}.toString() // Uncaught SyntaxError: Unexpected token '.'
    ({}).toString() // "[object Object]"
    [] + {} // "[object Object]" 【隐式转换为: "" + "[object Object]"】
    {} + []  // 0 【{}被解析为empty block了。这里本质上是对一个空数组执行正号运算,实际上就是把数组转型为数字。】
    [] + [] // "" 【隐式转换为两个空字符串相加】
    {} + {} // "[object Object][object Object]"
    ({} + []) // "[object Object]" 【{}被解析为空对象,本质上和上面的 []+{} 类似】
    

    参考:

    • 原文Object Plus Array Is Not Zero

    • Javascript 中 {}+[] === 0 为true因为啥

    • JS中{}+[]和[]+{}的返回值情况是怎样的?


    起源地下载网 » 【译】对象加数组不等于0(含自己总结)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元