摘要:這樣導致結果不一致,等解析語句為,對空對象強制轉為數(shù)字類型,即為,將非空字符串轉換為數(shù)字類型,結果為。綜上,右邊表達式轉換為。
首先從一系列讓JavaScript初學者抓狂的運算說起。
1 + {} {} + 1 [] + {} {} + [] [] + [] {} + {}
能全部答對上面的運算結果,不必浪費時間繼續(xù)閱讀本文了。
如果對某一些的結果還不確定,請慢慢往下看。
上面列的所有運算,需要理清以下兩點:
+和{}的解析規(guī)則;
JavaScript是如何進行類型轉換的;
+和{}的解析規(guī)則 +符號數(shù)字的加法運算,二元運算符
字符串的連接運算,二元運算符
正號,一元運算符,強制轉換其他類型的運算元為數(shù)字類型
{}符號對象的字面量
區(qū)塊語句
加法運算規(guī)則首先,我們來了解,+符號作為加號二元運算符的運算規(guī)則
使用ToPrimitive轉換左右運算元為原始數(shù)據(jù)類型值;
在第1步轉換后,如果有運算元出現(xiàn)原始數(shù)據(jù)類型為“字符串”類型時,則另一運算元強制轉換為字符串,然后做字符串連接運算;
其他情況時,所有運算元都轉換為原始數(shù)據(jù)類型為“數(shù)字”類型,然后做數(shù)字相加運算;
ToPrimitive運算從上圖總結ToPrimitive運算的語法說明:
ToPrimitive(input, PreferredType?)
input代表代入的值,而PreferredType可以是數(shù)字(Number)或字符串(String)其中一種,這會代表“優(yōu)先的”、“首選的”的要進行轉換到哪一種原始類型,轉換的步驟會依這里的值而有所不同。
但如果沒有提供這個值也就是預設情況,則會設置轉換的hint值為default。這個首選的轉換原始類型的指示(hint值),是在作內(nèi)部轉換時由JS視情況自動加上的,一般情況就是預設值。
轉換步驟為:
如果input是原始數(shù)據(jù)類型,則直接返回input。
否則,如果input是個對象時,則調(diào)用對象的valueOf()方法,如果能得到原始數(shù)據(jù)類型的值,則返回這個值。
否則,如果input是個對象時,調(diào)用對象的toString()方法,如果能得到原始數(shù)據(jù)類型的值,則返回這個值。
否則,拋出TypeError錯誤。
上面的步驟2與3對調(diào),轉換步驟為:
如果input是原始數(shù)據(jù)類型,則直接返回input。
否則,如果input是個對象時,則調(diào)用對象的toString方法,如果能得到原始數(shù)據(jù)類型的值,則返回這個值。
否則,如果input是個對象時,調(diào)用對象的valueOf()方法,如果能得到原始數(shù)據(jù)類型的值,則返回這個值。
否則,拋出TypeError錯誤。
有幾點值得注意:
數(shù)字是預設的PreferredType;
在一般情況下,加號運算中的對象要作轉型時,都是先調(diào)用valueOf再調(diào)用toString;
例外:Date 對象、Symbol 對象
Date 對象的預設首選類型是字符串(String);
Symbol 能顯示轉為字符串 String(Symbol) 和布爾值,不能轉為數(shù)字;
a + b: pa = ToPrimitive(a) pb = ToPrimitive(b) if(pa is string || pb is string) return concat(ToString(pa), ToString(pb)) else return add(ToNumber(pa), ToNumber(pb))
// ECMA-262, section 9.1, page 30. Use null/undefined for no hint, // (1) for number hint, and (2) for string hint. function ToPrimitive(x, hint) { if (!IS_SPEC_OBJECT(x)) return x; if (hint == NO_HINT) hint = (IS_DATE(x)) ? STRING_HINT : NUMBER_HINT; return (hint == NUMBER_HINT) ? DefaultNumber(x) : DefaultString(x); }
可以看出,Date類型的對象預設值為字符串(String)。
DefaultNumber和DefaultString方法
// ECMA-262, section 8.6.2.6, page 28. function DefaultString(x) { if (!IS_SYMBOL_WRAPPER(x)) { if (IS_SYMBOL(x)) throw MakeTypeError(kSymbolToString); var toString = x.toString; if (IS_SPEC_FUNCTION(toString)) { var s = % _CallFunction(x, toString); if (IsPrimitive(s)) return s; } var valueOf = x.valueOf; if (IS_SPEC_FUNCTION(valueOf)) { var v = % _CallFunction(x, valueOf); if (IsPrimitive(v)) return v; } } throw MakeTypeError(kCannotConvertToPrimitive); }
// ECMA-262, section 8.6.2.6, page 28. function DefaultNumber(x) { var valueOf = x.valueOf; if (IS_SPEC_FUNCTION(valueOf)) { var v = % _CallFunction(x, valueOf); if (IS_SYMBOL(v)) throw MakeTypeError(kSymbolToNumber); if (IS_SIMD_VALUE(x)) throw MakeTypeError(kSimdToNumber); if (IsPrimitive(v)) return v; } var toString = x.toString; if (IS_SPEC_FUNCTION(toString)) { var s = % _CallFunction(x, toString); if (IsPrimitive(s)) return s; } throw MakeTypeError(kCannotConvertToPrimitive); }
至此,我們弄清楚了ToPrimitive內(nèi)部運算規(guī)則。
原始數(shù)據(jù)類型轉換規(guī)則表對于原始數(shù)據(jù)類型直接的轉換規(guī)則就不一一解釋了,可以參看下表:
解析為數(shù)字1與空對象{}進行加運算,按照上面的規(guī)則,空對象{}按照valueOf -> toString順序,valueOf返回對象本身,所以調(diào)用toString返回"[object Object]"為字符串,根據(jù)規(guī)則,有一個為字符串,則進行字符串連接運算,數(shù)字1強制轉換為字符串"1",最終結果為"1[object Object]"。
{} + 1這個例子有坑,因為對于瀏覽器引擎來說,它們會認為以花括號開頭{的,是一個 區(qū)塊語句 的開頭,而不是一個對象字面量的語句,所以會認為略過第一個{}。所以這個例子相當于+1,加號運算會直接變?yōu)橐辉栠\算,對數(shù)字1強制轉換為數(shù)字類型,結果為1。
[] + {}將[]和{}分別調(diào)用ToPrimitive方法,返回""和"[object Object]",然后做字符串拼接得到"[object Object]"。
{} + []開始的{}被解析為區(qū)塊語句而略過,相當于+[],而[]轉為原始數(shù)據(jù)類型結果為"",強制轉換""為數(shù)字類型,結果為0;
[] + []將[]和{}分別調(diào)用ToPrimitive方法,返回""和"",然后做字符串拼接得到""。
{} + {}這個例子有爭議,對于Firefox和Edge瀏覽器來說,他們一以貫之的將第一個{}作為區(qū)塊語句略過,而對于V8引擎系列(Chrome、Node.js等)則將第一個{}解析為對象字面量。
這樣導致結果不一致,Firefox等解析語句為+{},對空對象{}強制轉為數(shù)字類型,即為+"[object Object]",將非空字符串轉換為數(shù)字類型,結果為NaN。
Chrome等解析語句為兩個空對象做加運算,結果也比較好理解:"[object Object][object Object]"。
這是一個不嚴格等于運算,我們來看轉換過程。
// 第一步,轉換右邊,根據(jù)上述原始數(shù)據(jù)類型轉換規(guī)則表, // 所有對象強制轉 Boolean 類型都是 true,所以 ![] 為 false ToPrimitive(![]) >> ToPrimitive(!ToBoolean([])) >> ToPrimitive(!true) >> ToPrimitive(false) >> 0 // 第二步,轉換左邊 ToPrimitive([]) >> "" // 第三步,判斷 "" == 0 >> ToNumber("") == 0 >> 0 == 0 >> return true++[[]][+[]] + [+[]]
進一步,來看這個例子。
很明顯,根據(jù)運算符優(yōu)先級,這個表達式可以用+分隔為左右兩個部分++[[]][+[]]和[+[]]。
可以看出這是一個數(shù)組里面有一個元素+[],而+[]即將[]強制轉換為數(shù)字類型,所以等于+"",結果為0。
綜上,右邊表達式轉換為[0]。
我們來一步步拆解, 根據(jù)對右邊表達式的轉換,這個表達式可以等同看做++([[]][0]),++后面又可以看做數(shù)組去第1個元素,表達式轉換為++[]。
但是當我們?nèi)g覽器執(zhí)行++[]時,報錯了:Uncaught ReferenceError: Invalid left-hand side expression in prefix operation。
嚇得我趕緊去看++的語法,原來++的運算是一種引用運算,即++[]應該轉換為:
var ref = [] ref = ref + 1
所以++[]轉換的正確姿勢為[] + 1。
左右進行相加得到:[] + 1 + [0]。
根據(jù)ToPrimitive運算規(guī)則,[] + 1 + [0] === "" + 1 + [0] === "1" + [0] === "10"。
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/108893.html
摘要:所謂裝箱轉換,正是把基本類型轉換為對應的對象,他是類型轉換中一種相當重要的種類。拆箱轉換在標準中,規(guī)定了函數(shù),它是對象類型到基本類型的轉換即,拆箱轉換。拆箱轉換會嘗試調(diào)用和來獲得拆箱后的基本類型。 JavaScript隱式類型轉換 基本數(shù)據(jù)類型 ECMAScript 一共定義了七種 build-in types,其中六種為 Primitive Value,Null, Undefined...
摘要:在編程語言中,能夠表示并操作的值的類型稱做數(shù)據(jù)類型。中的原始類型包括數(shù)字,字符串和布爾值。日期與時間語言核心包括構造函數(shù),用來創(chuàng)建表示日期和時間的對象。其規(guī)則為如果是布爾值,和分別被轉換為和如果是數(shù)字值,返回本身。 源代碼: https://github.com/RobinQu/Programing-In-Javascript/blob/master/chapters/Javas...
摘要:完整清單是中添加,此處不予介紹布爾值用來表示可能是真或假的值。結果抽象比較運算符在比較它們之前在類型之間進行自動轉換。中的隱式轉換稱為強制類型轉換,并在規(guī)范中定義。這些內(nèi)置類型可用于在不同類型之間進行顯式轉換。 翻譯:瘋狂的技術宅原文:https://www.valentinog.com/bl... 本文首發(fā)微信公眾號:前端先鋒歡迎關注,每天都給你推送新鮮的前端技術文章 show...
摘要:原始類型分別有類型類型和類型三種。類型中存在一個特殊的值叫。也可以把其他類型的數(shù)據(jù)自動轉換為類型運算符運算符判斷原始類型語法結構變量名稱。 數(shù)據(jù)類型 1.數(shù)據(jù)類型的概述;在JavaScript代碼中,能夠表示并且操作值的類型就叫做數(shù)據(jù)類型數(shù)據(jù)類型可以分成可變類型和不可變類型,可變類型的值是可以修改的。相反不可變類型的值是不可以修改的。數(shù)據(jù)類型還有原始類型(原始值)與引用類型(內(nèi)置對象)...
摘要:下面先看看涉及到的幾個函數(shù)以及他們的轉換規(guī)則,這個是需要記憶的內(nèi)容類型轉換需要使用到的函數(shù)對于布爾值用到的是對于數(shù)值,用到的是當然還有但是對于隱式類型轉換的時候,調(diào)用的是前者。 javaScript類型轉換規(guī)則 javaScript的類型轉換其實一直是很多前端開發(fā)人員很迷的地方,一會兒這里要轉換,一會兒那里又要轉換,總之就是一個大寫的迷,因為它隱式類型轉換的地方實在是太多了。 但其實...
摘要:下面分幾步來簡單的探探不同類型的轉換吧以下的內(nèi)容,都可以從權威指南中找到。其他值轉換成在編寫代碼的過程中,幾乎不用考慮它的取值類型。核心內(nèi)置類,會嘗試先于可以理解為對象優(yōu)先轉換成數(shù)字例外的是,利用的是轉換。 最近在寫公司的登錄注冊模塊,遇到類型不同相比較的時候,就心驚膽戰(zhàn),每次都要用瀏覽器來驗證一下,決定亂七八糟的隨便寫一下,方便日后自己回顧知識~ 弱類型帶來的那些讓人迷糊的事 弱類型...
閱讀 1762·2021-09-23 11:34
閱讀 2484·2021-09-22 15:45
閱讀 12996·2021-09-22 15:07
閱讀 2245·2021-09-02 15:40
閱讀 4151·2021-07-29 14:48
閱讀 1083·2019-08-30 15:55
閱讀 3252·2019-08-30 15:55
閱讀 2198·2019-08-30 15:55