说明
.[ ] ( )
字段访问、数组索引、函数调用和表达式分组
++ -- - ~ ! delete new typeof void
一元运算符、返回数据类型、对象创建、未定义的值
* / %
相乘、相除、求余数
+ - +
相加、相减、字符串串联
<< >> >>>
移位
< <= > >= instanceof
小于、小于或等于、大于、大于或等于、是否为特定类的实例
== != === !==
相等、不相等、全等,不全等
&
按位“与”
^
按位“异或”
|
按位“或”
&&
逻辑“与”
||
逻辑“或”
?:
条件运算
= OP=
赋值、赋值运算(如 += 和 &=)
,
多个计算根据此规则,我们把这一串运算分为以下16个子表达式:
运算符用红色标出,有一点可能大家会意识不到,其实中括号[]也是一个运算符,用来通过索引访问数组项,另外也可以访问字符串的子字符,有点类似charAt方法,如:'abcd'[1] // 返回'b'。而且中括号的优先级还是最高的哦。 预处理结束,接下来需要运用的就是javascript的类型转化知识了。我们先说说什么情况下需要进行类型转化。当caozuofu.html" target="_blank">操作符两边的操作数类型不一致或者不是基本类型(也叫原始类型)时,需要进行类型转化。先按运算符来分一下类:3. 通过ToString()把值转化成字符串, 直接看ECMA 9.8的表格http://es5.github.io/#x9.8
规则如下: 参数结果 undefined "undefined" null "null" boolean "true" 或者 "false" number 数字作为字符串。比如,"1.765" string 无需转换 规则就这么多,接下来实践一下,根据我们上面划分出的子表达式,一步一步将这个神奇的代码给执行出来。开工~ 先看最简单的子表达式16:+[] 只有一个操作数[],肯定是转化为number了,根据上面的规则2,[]是个数组,object类型,即对象。所以得先调用toPrimitive转化为原始类型,并且PreferredType为number,这个参数表示更“倾向于”转化的类型,这里肯定是number了。然后首先调用数组的valueOf方法,数组调用valueOf会返回自身,如下: 这个时候,我们得到一个空串“”,还没有结束,看上面的规则2描述,继续调用toNumber,转化为number类型,如下: 大功告成!子表达式16转化完毕,+[],最终得到0。 来看子表达式15:[~+""] 空串""前面有两个一元操作符,但是操作数还是只有一个,所以,最终要转化为的类型是number。看规则2吧,空串调用toNumber得到0。接下来是~,这是个什么东东呢?它是位运算符,作用可以记为把数字取负然后减一,所以~0就是-1 。 别忘了,这个子表达式外头还包着中括号,所以最终的值为[-1],即一个数组,里面只有一个元素-1. 接下来看子表达式13就简单了,把15、16求出来的填进去,就变成了这样:--[-1][0],取数组的第0个元素,然后自减,结果为-2,是不so easy! 继续往上走,子表达式14: [~+[]] 其实把15、和16的原理用上就非常明显了,答案[-1] 继续来求子表达式9,此刻它已变成:-2*[-1],有稍许不一样,不过没关系,我们还是按照规则来,运算符是乘号*,当然是做数学运算,那后面的[-1]就得转化为number,与16的求法类似,过程如下: ①调用toPrimitive,发现是object类型 ②调用valueOf,返回自身[-1] ③因为不是原始类型,继续调用toString,返回"-1" ④"-1"是原始类型了,然后调用toNumber,返回-1 ⑤与-2相乘,返回2 子表达式10:~~!+[],不多说了,答案1. 就是从右往左依次一元计算。 有了9和10,我们来到了子表达式4,此刻它已经长这样了:2+1, 好,我不多说了。 继续看表达式7:!(~+[]),~+[]=-1,这个根据上面已经知道了,那!-1是什么呢?这里要说一下这个感叹号,它是逻辑取非的意思,会把表达式转化为布尔类型,转化规则和js的Truthy和Falsy原则是一样的,后面跟数字的,除0以外都为false,后面跟字符串的,除空串以外都为false。这里的!-1当然就是false了。 接下来这个表达式3:false+{}有点关键。一个布尔加一个对象,那这个{}应该先转化为原始类型,流程如下: ①调用toPrimitive,发现是object类型 ②调用valueOf,返回自身{}, ③不是原始类型,调用toString,返回"[object Object]" ④false与"[object Object]"相加,false先转化为字符串"false" ⑤相加得结果"false[object Object]" 知道了表达式3和4,我们就可以来看表达式1了,此时它是这样的:"false[object Object]"[3],因为这个[]可以取字符串的子字符,像charAt一样,所以得到了结果"s" 经过上面艰难的流程,我们拿到了字符"s",也就是那张图的左半边,剩下的那个"b",相同的原理可以搞出来,我这里就不一一演示了,留给你练练吧~ 回顾一下这个过程其实也不复杂,只是有一些需要重复劳动的,只要你掌握了运算的优先级,能把大串分解成一个个小串,然后运用类型转化的知识挨个处理就搞定了。怎么样,看到这里你还觉得神奇吗? 如果有人瞧不起js,请把这段代码发给他,如果他想知道答案,请把本文发给他~ 参考资料:http://www.heyria.com/index.php/2014/01/js-object-plus-object/