javascript
JS中的加号+运算符详解
加號+運(yùn)算符
在 JavaScript 中,加法的規(guī)則其實(shí)很簡單,只有兩種情況:
- 把數(shù)字和數(shù)字相加
- 把字符串和字符串相加
所有其他類型的值都會被自動轉(zhuǎn)換成這兩種類型的值。 為了能夠弄明白這種隱式轉(zhuǎn)換是如何進(jìn)行的,我們首先需要搞懂一些基礎(chǔ)知識。
讓我們快速的復(fù)習(xí)一下。 在 JavaScript 中,一共有兩種類型的值:
- 原始值(primitives)
- undefined
- null
- boolean
- number
- string
- 對象值(objects):除了原始值外,其他的所有值都是對象類型的值,包括數(shù)組(array)和函數(shù)(function)。
類型轉(zhuǎn)換
加法運(yùn)算符會觸發(fā)三種類型轉(zhuǎn)換:
通過 ToPrimitive() 將值轉(zhuǎn)換為原始值
JavaScript 引擎內(nèi)部的抽象操作 ToPrimitive() 有著這樣的簽名:
ToPrimitive(input,PreferredType?)可選參數(shù) PreferredType 可以是 Number 或者 String。 它只代表了一個轉(zhuǎn)換的偏好,轉(zhuǎn)換結(jié)果不一定必須是這個參數(shù)所指的類型(汗),但轉(zhuǎn)換結(jié)果一定是一個原始值。 如果 PreferredType 被標(biāo)志為 Number,則會進(jìn)行下面的操作來轉(zhuǎn)換input
如果 PreferredType 被標(biāo)志為 String,則轉(zhuǎn)換操作的第二步和第三步的順序會調(diào)換。 如果沒有 PreferredType 這個參數(shù),則 PreferredType 的值會按照這樣的規(guī)則來自動設(shè)置:
- Date 類型的對象會被設(shè)置為 String
- 其它類型的值會被設(shè)置為 Number
通過 ToNumber() 將值轉(zhuǎn)換為數(shù)字
下面的表格解釋了 ToNumber() 是如何將原始值轉(zhuǎn)換成數(shù)字的
| undefined | NaN |
| null | +0 |
| boolean | true被轉(zhuǎn)換為1,false轉(zhuǎn)換為+0 |
| number | 無需轉(zhuǎn)換 |
| string | 由字符串解析為數(shù)字。例如,"324"被轉(zhuǎn)換為324 |
如果輸入的值是一個對象,則會首先會調(diào)用 ToPrimitive(obj, Number) 將該對象轉(zhuǎn)換為原始值, 然后在調(diào)用 ToNumber() 將這個原始值轉(zhuǎn)換為數(shù)字。
通過ToString()將值轉(zhuǎn)換為字符串
下面的表格解釋了 ToString() 是如何將原始值轉(zhuǎn)換成字符串的
| undefined | "undefined" |
| null | "null" |
| boolean | "true" 或者 "false" |
| number | 數(shù)字作為字符串。比如,"1.765" |
| string | 無需轉(zhuǎn)換 |
如果輸入的值是一個對象,則會首先會調(diào)用 ToPrimitive(obj, String) 將該對象轉(zhuǎn)換為原始值, 然后再調(diào)用 ToString() 將這個原始值轉(zhuǎn)換為字符串。
實(shí)踐一下
下面的對象可以讓你看到引擎內(nèi)部的轉(zhuǎn)換過程。
var obj = { valueOf: function () { console.log("valueOf"); return {}; // not a primitive }, toString: function () { console.log("toString"); return {}; // not a primitive } }Number 作為一個函數(shù)被調(diào)用(而不是作為構(gòu)造函數(shù)調(diào)用)時,會在引擎內(nèi)部調(diào)用 ToNumber() 操作:
> Number(obj) valueOf toString TypeError: Cannot convert object to primitive value加法
有下面這樣的一個加法操作。
value1 + value2在計算這個表達(dá)式時,內(nèi)部的操作步驟是這樣的
PreferredType 被省略,因此 Date 類型的值采用 String,其他類型的值采用 Number。
下面的表格就是 + 運(yùn)算符對于不同類型進(jìn)行運(yùn)算后,得到的結(jié)果類型
----------------------------------------------------------------------------------------| undefined | boolean | number | string | function | object | null | array ---------------------------------------------------------------------------------------- undefined | number | number | number | string | string | string | number | string boolean | number | number | number | string | string | string | number | string number | number | number | number | string | string | string | number | string string | string | string | string | string | string | string | string | string function | string | string | string | string | string | string | string | string object | string | string | string | string | string | string | string | string null | number | number | number | string | string | string | number | string array | string | string | string | string | string | string | string | string -------------------------------------------------------------------------------------------本表適用于 Chrome 13, Firefox 6, Opera 11 and IE9。
加法的示例
預(yù)料到的結(jié)果
當(dāng)你將兩個數(shù)組相加時,結(jié)果正是我們期望的:
> [] + [] ''[] 被轉(zhuǎn)換成一個原始值:首先嘗試 valueOf() 方法,該方法返回數(shù)組本身(this):
> var arr = []; > arr.valueOf() === arr true此時結(jié)果不是原始值,所以再調(diào)用 toString() 方法,返回一個空字符串(string 是原始值)。 因此,[] + [] 的結(jié)果實(shí)際上是兩個空字符串的連接。
將一個數(shù)組和一個對象相加,結(jié)果依然符合我們的期望:
> [] + {} '[object Object]'解析:將空對象轉(zhuǎn)換成字符串時,產(chǎn)生如下結(jié)果。
> String({}) '[object Object]'所以最終的結(jié)果其實(shí)是把 "" 和 "[object Object]" 兩個字符串連接起來。
更多的對象轉(zhuǎn)換為原始值的例子:
> 5 + new Number(7) 12 > 6 + { valueOf: function () { return 2 } } 8 > "abc" + { toString: function () { return "def" } } 'abcdef'意想不到的結(jié)果
如果 + 加法運(yùn)算的第一個操作數(shù)是個空對象字面量,則會出現(xiàn)詭異的結(jié)果(Firefox console 中的運(yùn)行結(jié)果):
> {} + {} NaN這個問題的原因是,JavaScript 把第一個 {} 解釋成了一個空的代碼塊(code block)并忽略了它。 NaN 其實(shí)是表達(dá)式 +{} 計算的結(jié)果 (+ 加號以及第二個 {})。 你在這里看到的 + 加號并不是二元運(yùn)算符「加法」,而是一個一元運(yùn)算符,作用是將它后面的操作數(shù)轉(zhuǎn)換成數(shù)字,和 Number() 函數(shù)完全一樣。例如:
> +"3.65" 3.65以下的表達(dá)式是它的等價形式:
+{} Number({}) Number({}.toString()) // {}.valueOf() isn’t primitive Number("[object Object]") NaN為什么第一個 {} 會被解析成代碼塊(code block)呢? 因?yàn)檎麄€輸入被解析成了一個語句:如果左大括號出現(xiàn)在一條語句的開頭,則這個左大括號會被解析成一個代碼塊的開始。 所以,你也可以通過強(qiáng)制把輸入解析成一個表達(dá)式來修復(fù)這樣的計算結(jié)果: (譯注:我們期待它是個表達(dá)式,結(jié)果卻被解析成了語句)
> ({} + {}) '[object Object][object Object]'一個函數(shù)或方法的參數(shù)也會被解析成一個表達(dá)式:
> console.log({} + {}) [object Object][object Object]經(jīng)過前面的講解,對于下面這樣的計算結(jié)果,你也應(yīng)該不會感到吃驚了:
> {} + [] 0在解釋一次,上面的輸入被解析成了一個代碼塊后跟一個表達(dá)式 +[]。 轉(zhuǎn)換的步驟是這樣的:
+[] Number([]) Number([].toString()) // [].valueOf() isn’t primitive Number("") 0有趣的是,Node.js 的 REPL 在解析類似的輸入時,與 Firefox 和 Chrome(和Node.js 一樣使用 V8 引擎) 的解析結(jié)果不同。 下面的輸入會被解析成一個表達(dá)式,結(jié)果更符合我們的預(yù)料:
> {} + {} '[object Object][object Object]' > {} + [] '[object Object]'轉(zhuǎn)載于:https://www.cnblogs.com/MasterYao/p/7783004.html
總結(jié)
以上是生活随笔為你收集整理的JS中的加号+运算符详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenID 和 OAuth 的区别及第
- 下一篇: iOS原生WebView中JavaScr