('b' + 'a' + + 'a' + 'a').toLowerCase()輸出banana的剖析

BlackHole1發表於2019-08-14

前言

今天逛微博的時候看到有個博主發的一個問題,程式碼如下:

('b' + 'a' + + 'a' + 'a').toLowerCase()
// "banana"
複製程式碼

當時第一反應是JavaScript會報錯,但是並沒有。然後就來了興趣

剖析

後來仔細一想,估計和JavaScript運算子優先順序、隱式轉化有關係。

於是先去MDN查了一下JavaScript運算子優先順序

我先把上面程式碼用到的運算子和優先順序列舉出來:

優先順序 運算型別 關聯性 運算子
20 圓括號 n/a (...)
16 一元正號 從右至左 + ...
13 加法 從左至右 ... + ...

OK,瞭解了上面的運算子後,我們現在來拆分下上面的程式碼

首先把toLowerCase去掉,這個函式沒啥用,只是起到一個迷惑的作用。

'b' + 'a' + + 'a' + 'a'
// to 
'b' + 'a' + (+ 'a') + 'a'
複製程式碼

這就是主要的,因為一元正號的優先順序是比加法高的,所以這裡用括號標註一下。

現在我們來看下一元正號的說明:

一元正號運算子位於其運算元前面,計算其運算元的數值,如果運算元不是一個數值,會嘗試將其轉換成一個數值。 儘管一元負號也能轉換非數值型別,但是一元正號是轉換其他物件到數值的最快方法,也是最推薦的做法,因為它不會對數值執行任何多餘操作。它可以將字串轉換成整數和浮點數形式,也可以轉換非字串值 true,false 和 null。小數和十六進位制格式字串也可以轉換成數值。負數形式字串也可以轉換成數值(對於十六進位制不適用)。如果它不能解析一個值,則計算結果為 NaN。

注意看上面的這段話:如果運算元不是一個數值,會嘗試將其轉換成一個數值如果它不能解析一個值,則計算結果為 NaN

那上面程式碼的+ 'a'就是會變成NaN,過程如下:

'b' + 'a' + (+ 'a') + 'a'
// to
'b' + 'a' + Number('a') + 'a'
// to
'b' + 'a' + NaN + 'a'
複製程式碼

是不是清晰很多了,然後又涉及到了隱式轉化,加號在JavaScript規則裡有一條是,當操作符有一個是字串型別時,另一個也要轉成字串型別。也就是說NaN要進行toString。那NaN在執行是什麼呢?在ECMA-262中有說明,如圖:

Imgur

也就是說NaN會轉成"NaN"。所以上面的程式碼就變成了這樣:

'b' + 'a' + NaN + 'a'
// to
'b' + 'a' + "NaN" + 'a'
複製程式碼

最終在呼叫toLowerCase函式轉成小寫,就變成了banana


更正:

沒有必要為了噴而噴,誠然文章的主體可能並不是說有什麼實用價值。但是研究本身就是一件充滿樂趣的事情。開心就好。

不喜歡,關閉就好。於其浪費時間噴一下,不如去看一下其他的文章。

相關文章