仓库源文站点原文


layout: post title: JavaScript 奇怪事件簿 modified: 2018-02-22 tags: [javascript] image: feature: abstract-3.jpg credit: dargadgetz creditlink: http://www.dargadgetz.com/ios-7-abstract-wallpaper-pack-for-iphone-5-and-ipod-touch-retina/ comments: true

share: true

JavaScript 中从来就没有什么奇怪的事件,我只是想梳理一下 javascript 中让人疑惑的表达式以及背后的原理。

说出这些表达式的结果:

如果想知道正确答案的话把表达式粘贴到浏览器的控制台执行即可

接下来的内容就是讲解这些表达式的结果是在什么样的原理下得出的

解决以上的问题的关键在于要搞明白三点:

  1. 操作符的使用方法和优先级
  2. 操作数在操作符的上下文中数据类型转化规则
  3. 语法中的特例

+ 操作符

+在 JavaScript 中有三个作用:

  1. 连接字符串:var result = 'Hello' + 'World'
  2. 计算数字之和:var result = 1 + 2
  3. 作为一元操作符:+variable

在表达式中+是操作符(operator),操作符操作的对象(上面例子中的HelloWorld12)名为操作数(operand)

一元+操作符的运算规则是:ToNumber(ToPrimitive(operand)),也就是把任意类型都转化为数字类型。

当操作数的数据类型不一致时,会根据以下规则进行转化:

所以根据以上规则,我们就能解释:

接下来我们说一说值得注意的情况

根据 Stackoverflow上的回答 这是因为 Chrome devtools 在执行代码的时候隐式的给表达式添加了括号(),实际上执行的代码是({} + {})。如果你在 IE 11 中执行({} + {}),就会得到[object Object][object Object]的结果

-操作符

虽然-操作符和+操作符看看上去性质相同,但-操作符只有一个功能,就是数值上的相减。它会尝试把非数值类型的操作数转化为数值类型,如果转化的结果是NaN, 那么表达式的结果可想而知也就是NaN,如果全部都转化成功,则执行减法操作,所以

==操作符

在 JavaScript 中===称为恒等操作符(The identity operator),==称为相等操作符(The equality operator)。因为篇幅关系在这里我们简单的针对题目聊聊后者

如果==操作符的操作数的数据类型不同:

  1. 如果一个操作数是null,并且另外一个操作数是undefined,他们是相等的
  2. 如果一个操作数是数值类型,并且另一个是字符串类型,那么把字符串类型转化为数值类型再进行比较
  3. 如果一个操作数是布尔类型,那么把true转化为1,false转化为0在进行比较
  4. 如果一个操作数是对象,另一个操作数是数字或者字符串,那么把对象转化为基本类型再进行比较

更全面=====的比较规则请参考: The legend of JavaScript equality operator

比较运算符><也遵循相似的规则: 1. 优先将字符串转化为数字进行比较;2. 将布尔类型转化为数字再进行比较,

isNaN

"NaN"是"Not a Number"的缩写,我们以为isNaN能够直接用来判断值是否是数字类型,但实际上并不可以。因为isNaN首先会强制将参数转化为数值类型,再进行判断。 这也就不难解释为什么isNaN(false)isNaN(null)返回都是true,因为falsenull都能被成功转化为数字0, 所以对于isNaN来说,它们是数字

结束

最后我们以表达式[[][[]]+[]][+[]][++[+[]][+[]]]作为文章的结尾

在这个表达式中出现了三种操作符,分别是

根据操作符的优先次序表,我们能确定操作符的优先级依次是: [] > 一元操作符+ > ++ > +

所以根据优先级我们首先可以计算出表达式的+[]部分,并且将表达式的这一部分用计算结果替换掉: [[][[]]+[]][0][++[0][0]]

接下来我们把表达式拆分为三部分看待: [ [][[]]+[] ] [0] [ ++[0][0] ]。如果还是不清晰的话,三部分从左到右分别是:

  1. [ [][[]]+[] ]
  2. [0]
  3. [ ++[0][0] ]

我们先看第一部分中+前面的 [][[]] 操作数,第一个[]是空数组,而紧跟着的[[]]是属性访问器(成员操作符),属性访问器内的[]会被强制转化为字符串类型,最终的结果即是空字符串'',所以第一个操作数的最终结果其实是[][''],即是undefined,而又因为+操作符的规则,最终[][[]]+[]表达式的结果是字符串'undefined',那么现阶段表达式的结果是['undefined'][0][++[0][0]],即'undefined'[++[0][0]]

接下来我们解决第三部分: [++[0][0]],我已经知道成员操作符[]的优先级要高于自增操作符++, 所以关于表达式++[0][0],我们需要首先计算[0][0],结果是0,之后计算++0的结果即是1

所以最终表达式转化为了'undefined'[1],最终的结果即是'n'

参考文章集合

https://www.site2share.com/folder/20020528