前言
這個世界總有那么些人喜歡較真,喜歡研究,這不, 在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.
附言
在這個提供分享和數字化的世界, 我們每天可能看到和學習了很多很多東西, 然后學習是一回事, 真正能學以致用, 將其在工作中融會貫通卻又是另外一回事. 我們學習的最終目的是解決問題和創造新的東西, 但怎么利用已有的知識去解決問題卻需要我們不斷總結和思考.
因此我這里翻譯這篇文章也不是僅僅給大家一個樂子, 更期待的是希望你和我能在新的一年中更好的去學會如果利用已知的和已有的資源去解決暫時可能的難題.
因為工作原因,很久沒寫東西, 在這個歲末旦初的時機終於再次提筆, 雖然只是翻譯, 但也算是對自己有所幫助吧, 希望也能給你帶來一些幫助.
水平有限, 如果有翻譯或者解釋不對的地方,還請大家多多諒解, 有磚請輕拍哈~~
最后, 也祝願園友元旦快樂,年終獎多多把!