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

資訊專欄INFORMATION COLUMN

關(guān)於 Javascript {} + {}

charles_paul / 2045人閱讀

摘要:於是其他的東西相加的時(shí)候?qū)?huì)被轉(zhuǎn)型成數(shù)字或者字串。整個(gè)過程即先依據(jù)轉(zhuǎn)換為原始型別,這裡要注意並不是最終結(jié)果,再來依據(jù)需要看是否要再將原生型別轉(zhuǎn)成數(shù)字或字串。這個(gè)結(jié)果等於只作的算。

這篇文章源自 What is {} + {} in JavaScript? 其實(shí)早在 2012 年就問世了。時(shí)至 2016 年末純粹是在聊天時(shí)重提這個(gè)問題,但由於年紀(jì)大了記憶力不佳,竟然記錯(cuò)了,所以才會(huì)有這一篇重新紀(jì)錄的筆記。

源頭是當(dāng)時(shí)由 Gary Bernhardt 在閃電秀中指出 Javascript 的詭異行為 - Wat

在開始之前我們先補(bǔ)充一下關(guān)於 Javascript 型別的整理

基礎(chǔ)型別(Primitive Type)

string

number

boolean

nudefined

null

symbol(ECMAScript 6)

物件型別(Object Type)

object

Function

Array

Date

其他

關(guān)於 Javascript 的加法其實(shí)是很簡(jiǎn)單的:原則上您只能夠?qū)?shù)字(Number)或字串(String)相加。
於是其他的東西相加的時(shí)候?qū)?huì)被轉(zhuǎn)型成數(shù)字或者字串。為了理解轉(zhuǎn)換的機(jī)制我們需要先釐清一些事情,我們得引用 ECMA-262 5.1 版規(guī)範(fàn)的 9.1 章節(jié)或新版 ECMA-262 7 的 7.1.1 的說明

讓我們來複習(xí)一下,在 Javascript 中關(guān)於型別的大分類 - 有兩種類型的

primitive 原生

object 物件

就像上面列出來的除了 undefined, null, boolean, number, string, symbol 之外的東西都是物件,當(dāng)然陣列和函式都是物件的一種。

轉(zhuǎn)換

加法運(yùn)算子整體來說會(huì)執(zhí)行三種類型的轉(zhuǎn)換,結(jié)果就是它會(huì)將轉(zhuǎn)成原生型別 primitive 中的 Number 或 String

1.1 使用 ToPrimitive() 將值先轉(zhuǎn)換成為原生型別

在內(nèi)部 ToPrimitive() 的使用調(diào)用格式為 ToPrimitive(input, PreferredType?)
第二個(gè)為可選參數(shù) PreferredType 值可以是 Number, String,這只是一個(gè)轉(zhuǎn)型偏好的註記,最終的結(jié)果可以是任一原生型別。
假設(shè) PreferredType 是 Number 那麼執(zhí)行轉(zhuǎn)換的步驟如下

如果輸入是原生型別,直接回傳

否則調(diào)用 obj.valueOf() 如果值是原生型別就回傳

還不是原生型別的話則調(diào)用 obj.toString() 結(jié)果如果是原生型別就回傳

否則拋出例外

如果 PreferredType 是 String 則 2, 3 步驟交換。
如果沒有 PreferredType 則 Date 預(yù)設(shè)為 String,其他型別則預(yù)設(shè)是 Number。

1.2 使用 ToNumber() 轉(zhuǎn)換為數(shù)字

下列說明 ToNumber() 是如何轉(zhuǎn)換原始型別為數(shù)字

undefined -> NaN

null -> +0

boolean

true -> 1

false -> +0

number -> 不轉(zhuǎn)換

string -> 將字串轉(zhuǎn)換成數(shù)字,不過這其中有些小細(xì)節(jié)下面整理給您,結(jié)果與 Number(input) 是一樣的

+"23.1" = 23.1

+"2e1" = 20

+"25px" = NaN

+"p23" = NaN

+"010" = 10

+"0xf" = 15

+[1] = 1

+[1, 2] = NaN

過程是這樣的:一個(gè)物件 obj 透過呼叫 ToPrimitive(obj, Number) 轉(zhuǎn)換成原始型別,接著在使用 ToNumber() 取得最後的結(jié)果

1.3 使用 ToString() 轉(zhuǎn)換為字串

下面說明 ToString() 如何轉(zhuǎn)換原生型別為字串

undefined -> "undefined"

null -> "null"

boolean

true -> "true"

false -> "false"

number -> "1.234"

string -> 不轉(zhuǎn)換

一個(gè)物件 obj 透過調(diào)用 ToPrimitive(obj, String) 轉(zhuǎn)換為原始型別,然後 ToString() 取得最後結(jié)果

1.4 實(shí)作

下面這個(gè)物件可以讓我們觀察轉(zhuǎn)換的過程

var obj = {
  valueOf: function () {
    console.log("valueOf")
    return {}
  },
  toString: function () {
    console.log("toString")
    return {}
  }
}

Number(obj)
+obj // 等價(jià)
> valueOf
> toString
> TypeError: can"t convert obj to number

當(dāng) Number() 作為 function 使用時(shí)內(nèi)部會(huì)執(zhí)行轉(zhuǎn)換 ToNumber() 的流程,根據(jù)上面的實(shí)作可以看出就如我們上面所敘述的規(guī)則流程一樣。
整個(gè)過程即先依據(jù) PreferredType 轉(zhuǎn)換為原始型別,這裡要注意並不是最終結(jié)果,再來依據(jù)需要看是否要再將原生型別轉(zhuǎn)成數(shù)字或字串。

加法

舉例下面的例子

val1 + val2

要解析上面這個(gè) expression 德遵循 ECMA-262 5.1 規(guī)範(fàn)的 11.6.1 章節(jié)或新版 ECAM-262 7 版的 12.8.3 說明的步驟:

(1). 轉(zhuǎn)換兩邊的運(yùn)算元為原生型別 Primitive

prim1 = ToPrimitive(val1)
prim2 = ToPrimitive(val2)

由於 PreferredType 被省略了,因此物件除了 Date 是代入 String 外,其他的是 Number。

(2). 兩數(shù)相加的情況下,如果 prim1 或 prim2 只有要一個(gè)是 String 那麼兩者都會(huì)被轉(zhuǎn)成字串,最終結(jié)果就是串接字串。

(3). 否則,兩者都會(huì)被轉(zhuǎn)成數(shù)字並加總。

到這一步可能造成困惑的地方:

+[] // Number("") = 0
[] + [] // "" + "" = ""
2.1 如同預(yù)期的結(jié)果

當(dāng)您執(zhí)行下面的範(fàn)例,兩個(gè)陣列相加

> [] + []
""

第一步使用 valueOf() 轉(zhuǎn)換兩個(gè)陣列 [] ,其會(huì)回傳陣列本身,因?yàn)檫€不是 Primitive 所以繼續(xù)使用 toString() 結(jié)果回傳一個(gè)空字串。
兩個(gè)空字串相加還是空字串。在只有單一 +[] 的狀況下 Javascript 會(huì)幫我們轉(zhuǎn)成數(shù)字 ToNumber(),一元運(yùn)算子和二元的行為有些差異。

第二個(gè)例子我們相加陣列和物件

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

空物件跟陣列一樣 valueOf() 還是物件,然後 toString() 物件會(huì)轉(zhuǎn)換成 [object Object] 相加就是上面的結(jié)果。

5 + new Number(7) // 12
6 + { valueOf: function () { return 2} } // 8
"abc" + { toString: function () { return "def"} } // "abcdef"
2.2 非預(yù)期的詭異結(jié)果

到這一步我們覺得已經(jīng)掌握了 Javascript,但 Javascript 可怕的地方就是總是可以給您驚喜驚嚇。
當(dāng)我們?cè)囍鴮蓚€(gè)物件實(shí)字 {} 相加時(shí)

> {} + {}
NaN

啥米鬼!? 造成這個(gè)問題的原因是 Javascript 把第一個(gè) {} 當(dāng)作是 code block 並忽略它。這個(gè)結(jié)果等於 Javascript 只作 +{} 的運(yùn)算。
上面有提過在 + 加號(hào)當(dāng)作一元運(yùn)算子的時(shí)候會(huì)嘗試把值轉(zhuǎn)成數(shù)字,下面就是等價(jià)執(zhí)行過程:

+{}
Number({})
Number({}.valueOf()) // 依然不是 Primitive 所以要繼續(xù)轉(zhuǎn)型
Number({}.toString())
Number("[object Object]")
NaN

那為什麼第一個(gè) {} 會(huì)被解析成程式片段而不是一個(gè)物件實(shí)字呢?因?yàn)?Javascript 將其解析為一個(gè) statement 。因此如果要處理這個(gè)問題我們可以透過 () 強(qiáng)迫 JS 將其視為 expression

({} + {})
// [object Object][object Object]"
var o = {} + {}
o // "[object Object][object Object]"

其他還有一些技巧,如果您想知道更多細(xì)節(jié)請(qǐng)參考重讀 Axel 的 Javascript 中的 Expression vs Statement 一文

經(jīng)過了上面的解釋,我想您就不會(huì)很驚訝下面這段程式的結(jié)果了

> {} + []
0
+[]
Number([])
Number([].valueOf()) // 依然不是 Primitive 所以要繼續(xù)轉(zhuǎn)型
Number([].toString())
Number("")
0

有趣的是 Node.js 的 REPL 解析輸入的方式和 Firefox, Chrome 等瀏覽器不同,它會(huì)將下面的輸入解析成 expression

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

這個(gè)結(jié)果就好像把 input 放到 console.log() 的參數(shù)內(nèi)一樣。

總結(jié)

在大多數(shù)的情況下,並不難理解 Javascript 加號(hào)的運(yùn)作,您只能相加數(shù)字或字串。物件會(huì)被轉(zhuǎn)換成數(shù)字或字串。當(dāng)然會(huì)造成混亂的還有一元運(yùn)算與二元運(yùn)算之間的行為差異這點(diǎn)值得注意一下,然後遵循上面談?wù)摰囊?guī)則,相信您應(yīng)該就能參透 Javascript 一些奇怪的行為。另外如果您想要合併陣列那您需要使用 Array.concat([3, 4])

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

如果是合併物件在快到 2017 的今天,您可以使用 Object.assign 或者其他函式庫例如 Underscore 等

var o1 = { a: 1, b: 2}
var o2 = { c: 3, d: 4}
Object.assign(o1, o2)
o1
/**
 {a: 1, b: 2, c: 3, d: 4}
 */
參考

Fake operator overloading in Javascript

Javascript values: not everything is an object

object plus object

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

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

相關(guān)文章

  • 深入 Javascript 執(zhí)行環(huán)境

    摘要:中的執(zhí)行環(huán)境與堆疊在這篇筆記中我將會(huì)深入的探討底層中的一些觀念,其中最重要的就是執(zhí)行環(huán)境。其他執(zhí)行環(huán)境都可以存取全域的東西。在這個(gè)階段直譯器會(huì)建立,透過掃描函式傳入的參數(shù),內(nèi)部的函式宣告,變數(shù)宣告。 Javascript 中的執(zhí)行環(huán)境與堆疊 在這篇筆記中我將會(huì)深入的探討 JS 底層中的一些觀念,其中最重要的就是執(zhí)行環(huán)境(Execution Context)。當(dāng)您閱讀完這篇文章後您可能會(huì)...

    levius 評(píng)論0 收藏0
  • [譯] Houdini: 你還沒聽說!這可能是 CSS 下一件最令人興奮的大事

    摘要:接下來我們將會(huì)更具體的說明是什麼東西和這傢伙會(huì)怎麼解決這些問題,並且列出目前開發(fā)中一些令人興奮的功能。這個(gè)功能甚至還沒有一個(gè)瀏覽器支援。完整的清單請(qǐng)查閱目前還未被寫入規(guī)範(fàn),意思是這邊提到任何內(nèi)容極有可能會(huì)改變。 譯者:其實(shí)...我想說這可能是最令我感到興奮..但又害怕頭痛的功能... 附上原文連結(jié) 你曾經(jīng)想要使用某個(gè) CSS 的新功能,但是最後卻因?yàn)檫@個(gè)功能瀏覽器還未全面支援而放棄了嗎...

    bergwhite 評(píng)論0 收藏0
  • 響應(yīng)式設(shè)計(jì)中百分比 % 的問題

    摘要:響應(yīng)式自適應(yīng)響應(yīng)式和自適應(yīng)設(shè)計(jì)共同點(diǎn)都是要處理在不同裝置下瀏覽網(wǎng)頁的問題,可讀性,版型等等。關(guān)於由於我們?nèi)詴?huì)在的設(shè)計(jì)中使用百分比,如此一來或多或少還是會(huì)受到進(jìn)位誤差的影響,因此並不是佈局的萬能藥。 showImg(https://segmentfault.com/img/remote/1460000006786975); 問題 為了要能夠解釋得更清楚我們需要實(shí)作一小段跟我們會(huì)遇到的問題...

    wangym 評(píng)論0 收藏0
  • [譯] 學(xué)習(xí) CSS clip-path 屬性

    摘要:整體來說網(wǎng)頁主要是由矩形所構(gòu)成的,另一方面印刷品則具備相對(duì)多樣性。即便我們?cè)O(shè)定的元素不再是矩形,但周圍的元素排列方式仍然維持原本矩形的佈局。為了達(dá)成周圍的元素跟著裁切的形狀,我們可以使用屬性。周圍的元素仍需要靠來修正。 整體來說網(wǎng)頁主要是由矩形所構(gòu)成的,另一方面印刷品則具備相對(duì)多樣性。造成這樣差異的原因有很多,不過其中一個(gè)即是缺少合適的工具。 這篇文章主要會(huì)介紹 clip-path 這...

    yuanxin 評(píng)論0 收藏0
  • 【譯】Headless Chrome 入門指南

    摘要:確切位置因平臺(tái)而異。如果以編程方式使用,這個(gè)頁面也是一個(gè)強(qiáng)大的調(diào)試工具,能看到所有原始的協(xié)議命令通過連線,於瀏覽器進(jìn)行通信。警告協(xié)議可以做很多有趣的事,但作為入門選項(xiàng)他令人沮喪。目前,提供了比協(xié)議高級(jí)別的。 本文翻譯自:Getting Started with Headless Chrome原文更新時(shí)間:July 28,2017作者:Eric Bidelman(Engineer @ G...

    toddmark 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<