成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript中,{}+{} 等于多少?

Jrain / 2702人閱讀

摘要:如果返回值是一個原始值,則返回這個原始值。如果或者中的任意一個為字符串,則將另外一個也轉(zhuǎn)換成字符串,然后返回兩個字符串連接操作后的結(jié)果。因此,的結(jié)果實際上是兩個空字符串的連接。

原文:What is {} + {} in JavaScript?

譯者:justjavac


最近,Gary Bernhardt 在一個簡短的演講視頻“Wat”中指出了一個有趣的 JavaScript 怪癖: 在把對象和數(shù)組混合相加時,會得到一些意想不到的結(jié)果。 本篇文章會依次講解這些計算結(jié)果是如何得出的。

在 JavaScript 中,加法的規(guī)則其實很簡單,只有兩種情況:

把數(shù)字和數(shù)字相加

把字符串和字符串相加

所有其他類型的值都會被自動轉(zhuǎn)換成這兩種類型的值。 為了能夠弄明白這種隱式轉(zhuǎn)換是如何進行的,我們首先需要搞懂一些基礎(chǔ)知識。

注意:在下面的文章中提到某一章節(jié)的時候(比如§9.1),指的都是 ECMA-262 語言規(guī)范(ECMAScript 5.1)中的章節(jié)。

讓我們快速的復(fù)習(xí)一下。 在 JavaScript 中,一共有兩種類型的值:

原始值(primitives)

undefined

null

boolean

number

string

對象值(objects)。

除了原始值外,其他的所有值都是對象類型的值,包括數(shù)組(array)和函數(shù)(function)。

類型轉(zhuǎn)換

加法運算符會觸發(fā)三種類型轉(zhuǎn)換:

轉(zhuǎn)換為原始值

轉(zhuǎn)換為數(shù)字

轉(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,則會進行下面的操作來轉(zhuǎn)換 input (§9.1):

如果 input 是個原始值,則直接返回它。

否則,如果 input 是一個對象。則調(diào)用 obj.valueOf() 方法。 如果返回值是一個原始值,則返回這個原始值。

否則,調(diào)用 obj.toString() 方法。 如果返回值是一個原始值,則返回這個原始值。

否則,拋出 TypeError 異常。

如果 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ù)字的 (§9.3)。

參數(shù) 結(jié)果
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)換成字符串的(§9.8)。

參數(shù) 結(jié)果
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)換為字符串。

實踐一下

下面的對象可以讓你看到引擎內(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

在計算這個表達式時,內(nèi)部的操作步驟是這樣的 (§11.6.1):

將兩個操作數(shù)轉(zhuǎn)換為原始值 (以下是數(shù)學(xué)表示法的偽代碼,不是可以運行的 JavaScript 代碼):

prim1 := ToPrimitive(value1)
prim2 := ToPrimitive(value2)

PreferredType 被省略,因此 Date 類型的值采用 String,其他類型的值采用 Number

如果 prim1 或者 prim2 中的任意一個為字符串,則將另外一個也轉(zhuǎn)換成字符串,然后返回兩個字符串連接操作后的結(jié)果。

否則,將 prim1 和 prim2 都轉(zhuǎn)換為數(shù)字類型,返回他們的和。

預(yù)料到的結(jié)果

當(dāng)你將兩個數(shù)組相加時,結(jié)果正是我們期望的:

> [] + []
""

[] 被轉(zhuǎn)換成一個原始值:首先嘗試 valueOf() 方法,該方法返回數(shù)組本身(this):

> var arr = [];
> arr.valueOf() === arr
true

此時結(jié)果不是原始值,所以再調(diào)用 toString() 方法,返回一個空字符串(string 是原始值)。 因此,[] + [] 的結(jié)果實際上是兩個空字符串的連接。

將一個數(shù)組和一個對象相加,結(jié)果依然符合我們的期望:

> [] + {}
"[object Object]"

解析:將空對象轉(zhuǎn)換成字符串時,產(chǎn)生如下結(jié)果。

> String({})
"[object Object]"

所以最終的結(jié)果其實是把 """[object Object]" 兩個字符串連接起來。

更多的對象轉(zhuǎn)換為原始值的例子:

> 5 + new Number(7)
12
> 6 + { valueOf: function () { return 2 } }
8
> "abc" + { toString: function () { return "def" } }
"abcdef"
意想不到的結(jié)果

如果 + 加法運算的第一個操作數(shù)是個空對象字面量,則會出現(xiàn)詭異的結(jié)果(Firefox console 中的運行結(jié)果):

> {} + {}
NaN

天哪!神馬情況?(譯注:原文沒有,是我第一次讀到這兒的時候感到太吃驚了,翻譯的時候加入的。) 這個問題的原因是,JavaScript 把第一個 {} 解釋成了一個空的代碼塊(code block)并忽略了它。 NaN 其實是表達式 +{} 計算的結(jié)果 (+ 加號以及第二個 {})。 你在這里看到的 + 加號并不是二元運算符「加法」,而是一個一元運算符,作用是將它后面的操作數(shù)轉(zhuǎn)換成數(shù)字,和 Number() 函數(shù)完全一樣。例如:

> +"3.65"
3.65

以下的表達式是它的等價形式:

+{}
Number({})
Number({}.toString())  // {}.valueOf() isn’t primitive
Number("[object Object]")
NaN

為什么第一個 {} 會被解析成代碼塊(code block)呢? 因為整個輸入被解析成了一個語句:如果左大括號出現(xiàn)在一條語句的開頭,則這個左大括號會被解析成一個代碼塊的開始。 所以,你也可以通過強制把輸入解析成一個表達式來修復(fù)這樣的計算結(jié)果: (譯注:我們期待它是個表達式,結(jié)果卻被解析成了語句,表達式和語句的區(qū)別可以查看我以前的『代碼之謎』系列的 語句與表達式。)

> ({} + {})
"[object Object][object Object]"

一個函數(shù)或方法的參數(shù)也會被解析成一個表達式:

> console.log({} + {})
[object Object][object Object]

經(jīng)過前面的講解,對于下面這樣的計算結(jié)果,你也應(yīng)該不會感到吃驚了:

> {} + []
0

在解釋一次,上面的輸入被解析成了一個代碼塊后跟一個表達式 +[]。 轉(zhuǎn)換的步驟是這樣的:

+[]
Number([])
Number([].toString())  // [].valueOf() isn’t primitive
Number("")
0

有趣的是,Node.js 的 REPL 在解析類似的輸入時,與 Firefox 和 Chrome(和Node.js 一樣使用 V8 引擎) 的解析結(jié)果不同。 下面的輸入會被解析成一個表達式,結(jié)果更符合我們的預(yù)料:

> {} + {}
"[object Object][object Object]"
> {} + []
"[object Object]"
3. 這就是所有嗎?

在大多數(shù)情況下,想要弄明白 JavaScript 中的 + 號是如何工作的并不難:你只能將數(shù)字和數(shù)字相加或者字符串和字符串相加。 對象值會被轉(zhuǎn)換成原始值后再進行計算。如果將多個數(shù)組相加,可能會出現(xiàn)你意料之外的結(jié)果,相關(guān)文章請參考在 javascript 中,為什么 [1,2] + [3,4] 不等于 [1,2,3,4]? 和 為什么 ++[[]][+[]]+[+[]] = 10?。

如果你想連接多個數(shù)組,需要使用數(shù)組的 concat 方法:

> [1, 2].concat([3, 4])
[1, 2, 3, 4]

JavaScript 中沒有內(nèi)置的方法來“連接" (合并)多個對象。 你可以使用一個 JavaScript 庫,比如 Underscore:

> var o1 = {eeny:1, meeny:2};
> var o2 = {miny:3, moe: 4};
> _.extend(o1, o2)
{eeny: 1, meeny: 2, miny: 3, moe: 4}

注意:和 Array.prototype.concat() 方法不同,extend() 方法會修改它的第一個參數(shù),而不是返回合并后的對象:

> o1
{eeny: 1, meeny: 2, miny: 3, moe: 4}
> o2
{miny: 3, moe: 4}

如果你想了解更多有趣的關(guān)于運算符的知識,你可以閱讀一下 “Fake operator overloading in JavaScript”(中文正在翻譯中)。

參考

JavaScript 并非所有的東西都是對象

JavaScript:將所有值都轉(zhuǎn)換成對象

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/77927.html

相關(guān)文章

  • 前端資源系列(5)-JavaScript奇味探索

    摘要:中有很多奇妙的東西,歸咎歸功于設(shè)計時候的迅速。缺陷有,但是的強大確實體現(xiàn)的淋漓盡致。它是如此的靈活,當(dāng)然隨之而來的便是開發(fā)的代價,它不像強類型語言那樣規(guī)規(guī)矩矩。難得周末晚上清閑,回味這些看起來有點怪怪卻又在發(fā)生著的問題。 JavaScript中有很多奇妙的東西,歸咎or歸功于設(shè)計時候的迅速。缺陷有,但是JavaScript的強大確實體現(xiàn)的淋漓盡致。 它是如此的靈活,當(dāng)然隨之而來的便是開...

    kyanag 評論0 收藏0
  • 數(shù)據(jù)類型 數(shù)值

    摘要:報錯報錯報錯有前導(dǎo)的數(shù)值會被視為八進制,但是如果前導(dǎo)后面有數(shù)字和,則該數(shù)值被視為十進制。對于那些會自動轉(zhuǎn)為科學(xué)計數(shù)法的數(shù)字,會將科學(xué)計數(shù)法的表示方法視為字符串,因此導(dǎo)致一些奇怪的結(jié)果。 1.概述1.1整數(shù)和浮點數(shù)1.2數(shù)值精度1.3數(shù)值范圍2.數(shù)值的表示法3.數(shù)值的進制4.特殊數(shù)值4.1正零和負零4.2NaN4.3Infinity5.與數(shù)值相關(guān)的全局方法5.1parseInt()5.2...

    lavor 評論0 收藏0
  • JavaScript 數(shù)據(jù)結(jié)構(gòu)與算法之美 - 歸并排序、快速排序、希爾排序、堆排序

    摘要:之所以把歸并排序快速排序希爾排序堆排序放在一起比較,是因為它們的平均時間復(fù)雜度都為。歸并排序是一種穩(wěn)定的排序方法。因此,快速排序并不穩(wěn)定。希爾排序思想先將整個待排序的記錄序列分割成為若干子序列。 showImg(https://segmentfault.com/img/bVbvpYZ?w=900&h=250); 1. 前言 算法為王。 想學(xué)好前端,先練好內(nèi)功,只有內(nèi)功深厚者,前端之路才...

    haitiancoder 評論0 收藏0
  • 2019-我的前端面試題

    摘要:先說下我面試情況,我一共面試了家公司。篇在我面試的眾多公司里,只有同城的面問到相關(guān)問題,其他公司壓根沒問。我自己回答的是自己開發(fā)組件面臨的問題。完全不用擔(dān)心對方到時候打電話核對的問題。 2019的5月9號,離發(fā)工資還有1天的時候,我的領(lǐng)導(dǎo)親切把我叫到辦公室跟我說:阿郭,我們公司要倒閉了,錢是沒有的啦,為了不耽誤你,你趕緊出去找工作吧。聽到這話,我虎軀一震,這已經(jīng)是第2個月沒工資了。 公...

    iKcamp 評論0 收藏0
  • 100塊錢換零錢,最多有多少種方式的 JavaScript 版本實現(xiàn)

    摘要:原文鏈接歡迎現(xiàn)在有塊錢人民幣,將塊錢換成零錢最小幣值元,一共有多少方式總的不同方式的數(shù)目等于將現(xiàn)金數(shù)換成除第一種幣值之外的所有其他硬幣的不同方式數(shù)據(jù),加上將現(xiàn)金數(shù)第一種幣值換成所有種類的幣值的不同方式,根據(jù)上面的說法來實現(xiàn)吧實現(xiàn)中的是中的 原文鏈接: 歡迎 Star 現(xiàn)在有100塊錢人民幣,將 100 塊錢換成零錢(最小幣值 1 元),一共有多少方式? 總的不同方式的數(shù)目等于: 將現(xiàn)...

    xeblog 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<