參加公司技術嘉年華第一季(前端、服務端)的間隙,陳導問了我一個問題:{}+[] 和 []+{}兩個表達式的值分別是什么?根據我的理解我覺得結果應該都是"[object Object]",但是結果卻並不是這樣子的({}+[] = 0 []+{} = '[object Object]'),我就想這不科學呀,一下子顛覆了我所學過的js知識了。於是我決定搞明白這究竟是是什么與原因導致的?
通過查找資料,發現之所以結果不一樣,是因為js解釋器把{}當做了代碼塊語法解析,那么{}+[]就變成+[],這樣的話很容易就解釋了上面兩個表達式的結果了~
為什么{}在右邊就沒有被解釋成代碼塊語法呢?這就要講到+運算符的用法,+可以做數字的加法和字符串的鏈接,只要有一個是字符串,另外一個就會數據類型轉換成字符串,然后進行拼接操作;都為對象的時候,這種情況下會通過valueOf獲取對象的值,如果原始值還是對象的話,會通過toString()方法,轉化成字符串。
下面解釋一下{}+[]和[]+{}的執行過程:
{}+[],由+運算符的語法可以知道,會從左向右解析,遇到{}被認為是代碼塊(語法)被忽略,繼續就變成了+[],此時+就不是加法運算符,也不是字符串連接符了,變成了轉換數字的運算符了,數組通過valueOf方法獲取值還是數組,執行toString方法后變成''空字符串,然后空字符串數據類型轉化成數字,就變成了0,也解釋了變種{}-[]=-0
[]+{},從左向右解析,[]被轉化成''空字符串,{}通過valueOf方法獲取原始值還是對象(注意不能通過{}.valurOf()獲取,此時{}會被解析成代碼塊),通過toString方法結果是'[object Object]',接下來解釋簡單的字符串連接問題了,所以結果是'[object Object]'。注:對象的toString和valueOf都不一樣,並且可以自定義。
擴展:由上面的例子,進而討論一下JS中數據類型轉換的問題
JS的取值特別靈活,會根據上下文語境,對數據進行隱式的轉換(當然也可以通過顯示的方法,對數據進行類型轉換)。一般情況下,這種數據類型轉換多用在運算符運算的時候.js的數據分成兩大類,原始值和對象,原始值有:null undefined string number boolean,其他都是對象。js引擎提供三種數據類型轉換操作:
ToPrimitive(),ToNumber(),ToString()。
toPrimitive()是將值轉化成原始值,有兩個參數,第一個需要轉換的數據,第二個參數是prefferedType(number或者string),處理的順序是:首先如果是原始值直接返回原始值,其次執行valueOf方法,如果返回原始值直接返回,如果不是,執行toString方法,轉化成字符串。
Date對象第二個參數是string(如果第二個參數是string的話,函數的處理順序應該把toString方法提到第二步),其他對象都是number。
第一個參數 | 是否是原始值 |
valueOf
|
toString
|
備注
|
new Obeject()
|
否 |
Object
|
'[object Object]'
|
|
new Number(1)
|
否 | 1 | '1' | 隱式轉換不是對象,可用Object.prototype.isPrototypeOf檢測 |
new Blooean(1)
|
否 | true | 'true' | 隱式轉換不是對象,可用Object.prototype.isPrototypeOf檢測 |
new Date()
|
否
|
1395985229639
|
‘
Fri Mar 28 2014 13:40:29 GMT+0800 (中國標准時間)
’
|
|
new Function('console.log(1);')
|
否
|
function anonymous() { console.log(1); }
|
'
function anonymous() { console.log(1); }
'
|
|
... |
...
|
...
|
...
|
toNumber將值轉化成數字。原始值轉換程數字如下表(對象參照
toPrimitive )
:
原始值 | 結果 |
null
|
+0
|
undefined
|
NAN |
123
|
123 |
'123' |
123
|
true/false
|
1/+0
|
toString將值轉化成字符串,原始值轉化成字符串如下表(對象參照toPrimitive ):
原始值 | 結果 |
null
|
'null' |
undefined
|
'undefined' |
123
|
'123' |
'123a' | '123a' |
true/false
|
'true'/'false'
|
參考資料:
《javascript權威指南(第六版)》