前言
这个世界总有那么些人喜欢较真,喜欢研究,这不, 在StackOverflow上,有人就很认真的提了这个问题, 幸运的是, 程序员永远是这个世界上最乐于帮助别人的人群之一, 于是, 真有人很热情的blabla的解释了原因.
想看源地址的可以去这里: http://stackoverflow.com/questions/7202157/can-you-explain-why-10
问题
++[[]][+[]]+[+[]]
在js中, 如果我们这样给一个变量赋值,不难发现它确实能返回一个值,而且还是10, 另外你可以在这里看到更多更多类似这样的测试结果.
那么, 为什么会返回值呢?为什么又是10呢?
原因
很多热心人士都给出了自己的解释, 这里我就不一一列举了, 我只翻译下最佳答案(他解释得最为详细).
1. 解决问题的最好的方式之一就是分解它, 然后分而治之, 这里也一样, 首先上述表达式可以分解为:+
[+[]]
2. 在js中, 表达式
+[]===0的结果为真, 这其实跟js编译器的设计有关的, 由于Js是弱类型语言,因此在我们想对某个对象进行一个操作时,js引擎总是会尝试先将这个对象转换为符合指定操作的对象类型然后再执行操作,在这里+会把后面[]转换为0然后执行别的结果,那么,上面的表达式可以进一步简化为下面这样子:
++[[]][0]
+
[0]由于[[]][0]表示取得数组[[]]的第一个元素, 因此我们可以得到:
[[]][0]返回该数组的内部数组([]),然而, 如果我们直接说[[]][0]===[]却不对, 为了避免错误的表述, 这里我们不放先称这个内部数组为A.
++[[]][0] == A+1, 因为在js中,++表示自增1.
++[[]][0] === +(A+1), 或者从另方面说,前面的结果永远是一个数字(js中,进行+1并不一定能保证结果是数字,但++得到的结果却永远是数字)
3. 让我们继续上面的步骤对表达式进一步简化, 这里我们把A替换为[],然后得到简化的结果:
+
[0]
在js中, 后面这个表达式的结果仍然为真: []+1 ==="1", 因为空数组转换为字符串等同于"", 根据这个特点,我们可以得到下面的结论:
- +([] +1) === +("" +1);
- +([] +1) === +("1");
- +([] +1) === 1.
4. 于是, 表达式可以进一步简化为下面这个结果:
1
[0]
我们不难发现[0] =="0"的结果同样为真, 这又是为啥呢? 其实原因跟上面一样的, 执行+的操作的时候, js引擎发现[0]是一个包含一个元素0的数组,因此,它会先将这个数组转换为字符串, 这样才能执行+操作(数组能匹配tostring的方法,但默认没有转换为数字的方式), 因此[0]会将其内部的所有元素拼接为一个字符串"0".
5. 好了, 到了揭晓答案的时刻啦, 通过上面的层层抽丝剥茧, 我们最终发现, 那么一大堆东西其实最后就是这样滴(数字+字符串=字符串):
+
"0"
=== "10"
Bazinga!!!
关于+[]
问题到这里结束了么? 应该没有,因为不少同学可能仍然对上面的解释有些疑问, 那么下面我们来补充下"+[]"把
首先看看一元操作符"+"的说明:
11.4.6 Unary + Operator
The unary + operator converts its operand to Number type.
The production UnaryExpression : + UnaryExpression is evaluated as follows:
Let expr be the result of evaluating UnaryExpression.
Return ToNumber(GetValue(expr)).
Object
Apply the following steps:
Let primValue be ToPrimitive(input argument, hint String).
Return ToString(primValue).
ToPrimitive()
的说明:
Object
Return a default value for the Object. The default value of an object is retrieved by calling the [[DefaultValue]] internal method of the object, passing the optional hint PreferredType. The behaviour of the [[DefaultValue]] internal method is defined by this specification for all native ECMAScript objects in 8.12.8.
[[DefaultValue]]
的说明:
8.12.8 [[DefaultValue]] (hint)
When the [[DefaultValue]] internal method of O is called with hint String, the following steps are taken:
Let toString be the result of calling the [[Get]] internal method of object O with argument "toString".
If IsCallable(toString) is true then,
a. Let str be the result of calling the [[Call]] internal method of toString, with O as the this value and an empty argument list.
b. If str is a primitive value, return str.
.toString方法的说明:
15.4.4.2 Array.prototype.toString ( )
When the toString method is called, the following steps are taken:
Let array be the result of calling ToObject on the this value.
Let func be the result of calling the [[Get]] internal method of array with argument "join".
If IsCallable(func) is false, then let func be the standard built-in method Object.prototype.toString (15.2.4.2).
Return the result of calling the [[Call]] internal method of func providing array as the this value and an empty arguments list.
这里, 我们再次回到关于+的定义:
11.4.6 Unary + Operator
The unary + operator converts its operand to Number type.
The production UnaryExpression : + UnaryExpression is evaluated as follows:
Let expr be the result of evaluating UnaryExpression.
Return ToNumber(GetValue(expr)).
因此呢, +"" === 0, 从而, +[] ===0.
附言
在这个提供分享和数字化的世界, 我们每天可能看到和学习了很多很多东西, 然后学习是一回事, 真正能学以致用, 将其在工作中融会贯通却又是另外一回事. 我们学习的最终目的是解决问题和创造新的东西, 但怎么利用已有的知识去解决问题却需要我们不断总结和思考.
因此我这里翻译这篇文章也不是仅仅给大家一个乐子, 更期待的是希望你和我能在新的一年中更好的去学会如果利用已知的和已有的资源去解决暂时可能的难题.
因为工作原因,很久没写东西, 在这个岁末旦初的时机终于再次提笔, 虽然只是翻译, 但也算是对自己有所帮助吧, 希望也能给你带来一些帮助.
水平有限, 如果有翻译或者解释不对的地方,还请大家多多谅解, 有砖请轻拍哈~~
最后, 也祝愿园友元旦快乐,年终奖多多把!
出处:http://jujusharp.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。