前段時間看到一道題,如下:([][[]]+[])[+!![]]+([]+{})[!+[]+!![]]問最終列印結果,然後簡單瞭解一下js的裝箱,拆箱操作。 基本 1. 裝箱操作: 就是將基本類型(String, Number, Boolean)轉為引用類型 2. 拆箱操作: 與裝箱相反,就是將引用類 ...
前段時間看到一道題,如下:([][[]]+[])[+![]]+([]+{})[!+[]+![]]問最終列印結果,然後簡單瞭解一下js的裝箱,拆箱操作。
基本
- 裝箱操作: 就是將基本類型(String, Number, Boolean)轉為引用類型
- 拆箱操作: 與裝箱相反,就是將引用類型轉為基本類型, 常用的基本方法有: valueof , toString()
分析
像上面的那個題目,主要是拆箱操作,下麵就來簡單拆解分析一下吧:
1. 基礎:
[] ==> [] (Array);
[[]] ==> [array(0)] (Array);
[]+[[]] ???
ok, 我們簡單來瞭解一下js中的+運算符:
+:一般是用於對象相加的,這是在兩個對象都是Number的情況下。那其他類型下就涉及到隱式轉換,下麵看下隱式轉換的規則
1. 如果一個對象是String,那麼就要將另一個對象轉換為String再進行字元串拼接
2. 如果對象都是複雜類型,那麼就要將兩個對象均轉化為String,再進行拼接。
至於如果對象是其他簡單類型(Number, Boolean),就要先將對象轉化為Number再進行運算
所以 []+[[]] ==> String([]) + String([[]]) == "" + "" ==> ""
2. 拆解:
然後我們來看下題目,簡單拆分為4部分:
1. ([][[]]+[])
[][[]] 這部分乍一眼看過去會覺得很蒙,但我們已經知道[] ==> Array,常用的獲取Array中的數據的方法有Array[]
所以,讓我們來拆解下吧:
首先為了更清楚,將最左側的[]賦值給 father ==> var father = [];
將右側[]中的[]賦值給child ==> var child = [];
即最終 [][[]] == father[child] == "undefined"
[][[]] + [] == String("undefined") + String([]) == "undefined"
2. [+!![]]
關於這一部分,我們需要瞭解一下!!
!!: 一般來說,似乎大家普遍認為是將對象取反,再取反,即雙重否定。但其實應該是將對象強制轉換為Boolean類型。
關於Boolean中,需要關註,{}和[]轉換為Boolean時是true.
[+!![]] ==>[+true] ==> [Number(true)] ==> [1]
3. ([]+{})
這一部分就很簡單了: []+{} ==> String([]) + String({}) == "" + "[object Object]".
但是,如果將上面兩個對象調轉位置呢:
{} + [] : 按常規來說,應該是和上面一樣的結果,但是最終的列印結果卻是0,這是為什麼呢。
js中{} 不僅可以代表一個對象,同時也有可能是一個代碼塊,有些時候,js會將寫在前面的{}解釋為代碼塊,於是參與運算的其實就只有+[]了。
4. [!+[]+!![]]
經過上面部分,這裡也很清楚了:
!+[] ==> ! + String([]) == !+"" == !"" == true
[true + !![]] == [true + true] = [Number(true) + Number(true)] == [2]
所以最後的結果: "undefined"[1] + "[object Object]"[2] == "nb";
通過上面的題目,應該已經大致瞭解了關於拆箱的一些基礎了。這樣,下次看到就不會一頭霧水了。