JavaScript 加法規則
在JavaScript中,加法的規則其實很簡單,只有兩種情況:
數位和數位相加
字串和字串相加
所有其他型別的值都會被自動轉換成這兩種型別的值
在JavaScript中,一共有兩種型別的值:
原始值有:undefined、null、 布林值(boolean)、 數位(number)、字串(string)、symbol
物件值:其他的所有值都是物件型別的值,包括陣列(arrays)和函數(functions)
型別轉換
加法運運算元會觸發三種型別轉換:將值轉換為原始值、轉換為數位、轉換為字串,這剛好對應了JavaScript引擎內部的三種抽象操作:ToPrimitive()、ToNumber()、ToString()
通過 ToPrimitive() 將值轉換為原始值
ToPrimitive(input, PreferredType?)
可選引數PreferredType可以是Number或者String,它只代表了一個轉換的偏好,轉換結果不一定必須是這個引數所指的型別,但轉換結果一定是一個原始值.如果PreferredType被標誌為Number,則會進行下面的操作來轉換輸入的值 (§9.1):
如果輸入的值已經是個原始值,則直接返回它.
否則,如果輸入的值是一個物件.則呼叫該物件的valueOf()方法.如果valueOf()方法的返回值是一個原始值,則返回這個原始值.
否則,呼叫這個物件的toString()方法.如果toString()方法的返回值是一個原始值,則返回這個原始值.
否則,丟擲TypeError異常.
如果PreferredType被標誌為String,則轉換操作的第二步和第三步的順序會調換.如果沒有PreferredType這個引數,則PreferredType的值會按照這樣的規則來自動設定: Date型別的物件會被設定為String,其它型別的值會被設定為Number.
通過ToNumber()將值轉換為數位
如果輸入的值是一個物件,則會首先會呼叫ToPrimitive(obj, Number)將該物件轉換為原始值,然後在呼叫ToNumber()將這個原始值轉換為數位.
通過ToString()將值轉換為字串
如果輸入的值是一個物件,則會首先會呼叫ToPrimitive(obj, String)將該物件轉換為原始值,然後再呼叫ToString()將這個原始值轉換為字串.
demo
var obj = { valueOf: function () { console.log("valueOf"); return {}; // 沒有返回原始值 }, toString: function () { console.log("toString"); return {}; // 沒有返回原始值 } }
Number作為一個函數被呼叫(而不是作為建構函式呼叫)時,會在引擎內部呼叫ToNumber()操作:
Number(obj) // output valueOf toString Uncaught TypeError: Cannot convert object to primitive value String(obj) // output toString valueOf Uncaught TypeError: Cannot convert object to primitive value
加法
value1 + value2
在計算這個表示式時,操作步驟是這樣的:
將兩個運算元轉換為原始值 (下面是數學表示法,不是JavaScript程式碼):
prim1 := ToPrimitive(value1) prim2 := ToPrimitive(value2)
PreferredType被省略,因此 Date 型別的值採用String,其他型別的值採用Number.
如果 prim1 或者 prim2 中的任意一個為字串,則將另外一個也轉換成字串,然後返回兩個字串連線操作後的結果;
否則,將 prim1 和 prim2 都轉換為數位型別,返回他們的和。
[]+[]
輸出: ''
[]會被轉換成一個原始值,首先嚐試 valueOf() 方法,返回陣列本身(this):
> var arr = []; > arr.valueOf() === arr true
這樣的結果不是原始值,所以再呼叫 toString() 方法,返回一個空字串(是一個原始值)。因此,[] + [] 的結果實際上是兩個空字串的連線.
> [] + {} '[object Object]'
{} + {}
輸出:NaN
JavaScript引擎將第一個{}解釋成了一個空的程式碼塊並忽略了它
這裡的加號並不是代表加法的二元運運算元,而是一個一元運運算元,作用是將它後面的運算元轉換成數位,和 Number() 函數完全一樣。例如:
+{} Number({}) Number({}.toString()) // 因為{}.valueOf()不是原始值 Number("[object Object]") NaN
> {} + [] 0
{} 忽略
+[] = Number([]) = Number([].toString()) = Number("") = 0
有趣的是,Node.js的REPL在解析類似的輸入時,與Firefox和Chrome(和Node.js一樣使用V8引擎)的解析結果不同.下面的輸入會被解析成一個表示式,結果更符合我們的預料:
> {} + {} '[object Object][object Object]' > {} + [] '[object Object]'
總結
物件.valueOf() === 物件
陣列物件.toString() === 陣列物件.join()
物件.toString() === "[object Object]"
Javacript 中 + 號工作:
數位 + 數位
字串 + 字串
【相關推薦:】
以上就是JavaScript型別轉換(詳解及範例)的詳細內容,更多請關注TW511.COM其它相關文章!