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

資訊專欄INFORMATION COLUMN

從 ++[[]][+[]]+[+[]]==10? 深入淺出弱類型 JS 的隱式轉(zhuǎn)換

miya / 1930人閱讀

摘要:與此相對,強類型語言的類型之間不一定有隱式轉(zhuǎn)換。三為什么是弱類型弱類型相對于強類型來說類型檢查更不嚴格,比如說允許變量類型的隱式轉(zhuǎn)換,允許強制類型轉(zhuǎn)換等等。在中,加性運算符有大量的特殊行為。

從++[[]][+[]]+[+[]]==10?深入淺出弱類型JS的隱式轉(zhuǎn)換

本文純屬原創(chuàng)? 如有雷同? 純屬抄襲? 不甚榮幸! 歡迎轉(zhuǎn)載!

原文收錄在【我的GitHub博客】,覺得本文寫的不算爛的,可以點擊【我的GitHub博客】順便登錄一下賬號給個星星?鼓勵一下,關(guān)注最新更新動態(tài),大家一起多交流學習,歡迎隨意轉(zhuǎn)載交流,不要錢,文末沒有福利哦?,你懂的?。

如果你很直接,就是直白想看我的結(jié)果分析,請直接跳到[第六章](),只要你看的懂,前面的知識點可以忽略。

起因

凡是都有一個來源和起因,這個題不是我哪篇文章看到的,也不是我瞎幾把亂造出來的,我也沒這個天賦和能力,是我同事之前丟到群里,叫我們在瀏覽器輸出一下,對結(jié)果出乎意料,本著實事求是的精神,探尋事物的本質(zhì),不斷努力追根溯源,總算弄明白了最后的結(jié)果,最后的收獲總算把js的隱式類型轉(zhuǎn)換刨根問底的搞清楚了,也更加深入的明白了為什么JS是弱類型語言了。

題外話

一看就看出答案的大神可以跳過,鄙文會浪費你寶貴的時間,因為此文會很長,涉及到知識點很多很雜很細,以及對js源碼的解讀,而且很抽象,如果沒有耐心,也可以直接跳過,本文記錄本人探索這道問題所有的過程,會很長。

可能寫的不太清楚,邏輯不太嚴密,存在些許錯誤,還望批評指正,我會及時更正。去年畢業(yè)入坑前端一年,并不是什么老鳥,所以我也是以一個學習者的身份來寫這篇文章,逆向的記錄自己學習探索的過程,并不是指點江山,揮斥方遒,目空一切的大神,如果寫的不好,還望見諒。

首先對于這種問題,有人說是閑的蛋疼,整天研究這些無聊的,有啥用,開發(fā)誰會這么寫,你鉆牛角尖搞這些有意思嗎?

對于這種質(zhì)疑,我只能說:愛看不看,反正不是寫給你看。

當然,這話也沒錯,開發(fā)過程中確實不會這么寫,但是我們要把開發(fā)和學習區(qū)分開來,很多人開發(fā)只為完成事情,不求最好,但求最快,能用就行?。學習也是這樣,停留在表面,會用API就行,不會去深層次思考原理,因此很難進一步提升,就是因為這樣的態(tài)度才誕生了一大批一年經(jīng)驗重復(fù)三五年的API大神?。

但是學習就不同,學習本生就是一個慢慢深入,尋根問底,追根溯源的過程,如果對于探尋問題的本質(zhì)追求都沒有,我只能說做做外包就好,探究這種問題對于開發(fā)確實沒什么卵用,但是對我們了解JavaScript這門語言卻有極大的幫助,可以讓我們對這門語言的了解更上一個臺階。JavaScript為什么是弱類型語言,主要體現(xiàn)在哪里,弱類型轉(zhuǎn)換的機制又是什么?

有人還是覺得其實這對學習JS也沒什么多大卵用,我只能說:我就喜歡折騰,你管得著?反正我收獲巨多就夠了。

++[[]][+[]]+[+[]]===10?這個對不對,我們先不管,先來看幾個稍微簡單的例子,當做練習入手。
?

一、作業(yè)例子:

這幾個是留給大家的作業(yè),涉及到的知識點下面我會先一一寫出來,為什么涉及這些知識點,因為我自己一步步踩坑踩過來的,所以知道涉及哪些坑,大家最后按照知識點一步一步分析,一定可以得出 答案來,列出知識點之后,我們再來一起分析++[[]][+[]]+[+[]]===10?的正確性。

{}+{}//chrome:"object Object",F(xiàn)irfox:NaN

{}+[]//0

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

首先,關(guān)于1、2和3這三個的答案我是有一些疑惑,先給出答案,希望大家看完這篇文章能和我討論一下自己的想法,求同存異。

4.{}+1

5.({}+1)

6.1+{}

7.[]+1

8.1+[]

9.1-[]

10.1-{}

11.1-!{}

12.1+!{}

13.1+"2"+"2"

14.1+ +"2"+"2"

15.1++"2"+"2"

16.[]==![]

17.[]===![]

這幾個例子是我隨便寫的,幾乎包含了所有弱類型轉(zhuǎn)換所遇到的坑,為什么會出現(xiàn)這種情況,就不得不從JS這門語言的特性講起,大家都知道JS是一門動態(tài)的弱類型語言,那么你有沒有想過什么叫做弱類型?什么叫做動態(tài)?大家都知道這個概念,但有沒有進一步思考呢?

今天通過這幾個例子就來了解一下JS的弱類型,什么是動態(tài)暫時不做探討。
??

二、強弱類型的判別

按照計算機語言的類型系統(tǒng)的設(shè)計方式,可以分為強類型和弱類型兩種。二者之間的區(qū)別,就在于計算時是否可以不同類型之間對使用者透明地隱式轉(zhuǎn)換。從使用者的角度來看,如果一個語言可以隱式轉(zhuǎn)換它的所有類型,那么它的變量、表達式等在參與運算時,即使類型不正確,也能通過隱式轉(zhuǎn)換來得到正確地類型,這對使用者而言,就好像所有類型都能進行所有運算一樣,所以這樣的語言被稱作弱類型。與此相對,強類型語言的類型之間不一定有隱式轉(zhuǎn)換。
??

三、JS為什么是弱類型?

弱類型相對于強類型來說類型檢查更不嚴格,比如說允許變量類型的隱式轉(zhuǎn)換,允許強制類型轉(zhuǎn)換等等。強類型語言一般不允許這么做。具體說明請看維基百科的說明。

根據(jù)強弱類型的判別定義,和上面的十幾個例子已經(jīng)充分說明JavaScript 是一門弱類型語言了。

?先講一講一些概念,要想弄懂上面題目答案的原理,首先你要徹底弄懂以下的概念,有些時候?qū)σ恍〇|西似懂非懂,其實就是對概念和規(guī)則沒有弄透,弄透之后等會回過頭對照就不難理解,不先了解透這些后面的真的不好理解,花點耐心看看,消化一下,最后串通梳理一下,一層一層的往下剝,答案迎刃而解。

? 為了能夠弄明白這種隱式轉(zhuǎn)換是如何進行的,我們首先需要搞懂如下一些基礎(chǔ)知識。如果沒有耐心,直接跳到后面第四章[4.8 小結(jié)]()我總結(jié)的幾條結(jié)論,這里僅給想要一步步通過過程探尋結(jié)果的人看。

??

四、ECMAScript的運算符、{}解析、自動分號插入 4.1 ECMAScript 運算符優(yōu)先級
運算符 描述
. [] () 字段訪問、數(shù)組下標、函數(shù)調(diào)用以及表達式分組
++ — - + ~ ! delete new typeof void 一元運算符、返回數(shù)據(jù)類型、對象創(chuàng)建、未定義值
* / % 乘法、除法、取模
+ - + 加法、減法、字符串連接
<< >> >>> 移位
< <= > >= instanceof 小于、小于等于、大于、大于等于、instanceof
== != === !== 等于、不等于、嚴格相等、非嚴格相等
& 按位與
^ 按位異或
按位或
&& 邏輯與
邏輯或
?: 條件
= oP= 賦值、運算賦值
, 多重求值
4.2 ECMAScript 一元運算符(+、-)

一元運算符只有一個參數(shù),即要操作的對象或值。它們是 ECMAScript 中最簡單的運算符。

delete,void--,++這里我們先不扯,免得越扯越多,防止之前博文的啰嗦,這里咋們只講重點,有興趣的可以看看w3school(點我查看)對這幾個的詳細講解。

上面的例子我們一個一個看,看一個總結(jié)一個規(guī)則,基本規(guī)則上面例子幾乎都包含了,如有遺漏,還望反饋補上。

這里我們只講 一元加法一元減法

我們先看看ECMAScript5規(guī)范(熟讀規(guī)范,你會學到很多很多)對一元加法和一元減法的解讀,我們翻到11.4.6和11.4.7。

其中涉及到幾個ECMAScript定義的抽象操作,ToNumber(x),ToPrimitive(x)等等 下一章詳細解答,下面出現(xiàn)的抽象定義也同理,先不管這個,有基礎(chǔ)想深入了解可以提前熟讀ECMAScript5規(guī)范(點擊查看)。

規(guī)范本來就是抽象的東西,不太好懂不要緊,我們看看例子,這里的規(guī)范我們只當做一種依據(jù)來證明這些現(xiàn)象。

大多數(shù)人都熟悉一元加法和一元減法,它們在 ECMAScript 中的用法與您高中數(shù)學中學到的用法相同。
一元加法本質(zhì)上對數(shù)字無任何影響:

var iNum = 20;
iNum = +iNum;//注意不要和iNum += iNum搞混淆了;
alert(iNum);    //輸出 "20"

盡管一元加法對數(shù)字無作用,但對字符串卻有有趣的效果,會把字符串轉(zhuǎn)換成數(shù)字。

var sNum = "20";
alert(typeof sNum); //輸出 "string"
var iNum = +sNum;
alert(typeof iNum); //輸出 "number"

這段代碼把字符串 "20" 轉(zhuǎn)換成真正的數(shù)字。當一元加法運算符對字符串進行操作時,它計算字符串的方式與 parseInt() 相似,主要的不同是只有對以 "0x" 開頭的字符串(表示十六進制數(shù)字),一元運算符才能把它轉(zhuǎn)換成十進制的值。因此,用一元加法轉(zhuǎn)換 "010",得到的總是 10,而 "0xB" 將被轉(zhuǎn)換成 11。

另一方面,一元減法就是對數(shù)值求負(例如把 20 轉(zhuǎn)換成 -20):

var iNum = 20;
iNum = -iNum;
alert(iNum);    //輸出 "-20"

與一元加法運算符相似,一元減法運算符也會把字符串轉(zhuǎn)換成近似的數(shù)字,此外還會對該值求負。例如:

var sNum = "20";
alert(typeof sNum); //輸出 "string"
var iNum = -sNum;
alert(iNum);        //輸出 "-20"
alert(typeof iNum); //輸出 "number"

在上面的代碼中,一元減法運算符將把字符串 "-20" 轉(zhuǎn)換成 -20(一元減法運算符對十六進制和十進制的處理方式與一元加法運算符相似,只是它還會對該值求負)。
??

4.3 ECMAScript 加法運算符(+)

在多數(shù)程序設(shè)計語言中,加性運算符(即加號或減號)通常是最簡單的數(shù)學運算符。
在 ECMAScript 中,加性運算符有大量的特殊行為。

我們還是先看看ECMAScript5規(guī)范(熟讀規(guī)范,你會學到很多很多)對加號運算符 ( + )解讀,我們翻到11.6.1。

前面讀不懂不要緊,下一章節(jié)會為大家解讀這些抽象詞匯,大家不要慌,但是第七條看的懂吧, 這就是為什么1+"1"="11"而不等于2的原因 ,因為規(guī)范就是這樣的,瀏覽器沒有思維只會按部就班的執(zhí)行規(guī)則,所以規(guī)則是這樣定義的,所以最后的結(jié)果就是規(guī)則規(guī)定的結(jié)果,知道規(guī)則之后,對瀏覽器一切運行的結(jié)果都會豁然開朗,哦,原來是這樣的啊。

在處理特殊值時,ECMAScript 中的加法也有一些特殊行為:

某個運算數(shù)是 NaN,那么結(jié)果為 NaN。

-Infinity 加 -Infinity,結(jié)果為 -Infinity。

Infinity 加 -Infinity,結(jié)果為 NaN。

+0 加 +0,結(jié)果為 +0。

-0 加 +0,結(jié)果為 +0。

-0 加 -0,結(jié)果為 -0。

不過,如果某個運算數(shù)是字符串,那么采用下列規(guī)則:

如果兩個運算數(shù)都是字符串,把第二個字符串連接到第一個上。

如果只有一個運算數(shù)是字符串,把另一個運算數(shù)轉(zhuǎn)換成字符串,結(jié)果是兩個字符串連接成的字符串。

例如:

var result = 5 + 5; //兩個數(shù)字
alert(result);      //輸出 "10"
var result2 = 5 + "5";  //一個數(shù)字和一個字符串
alert(result);      //輸出 "55"

這段代碼說明了加法運算符的兩種模式之間的差別。正常情況下,5+5 等于 10(原始數(shù)值),如上述代碼中前兩行所示。不過,如果把一個運算數(shù)改為字符串 "5",那么結(jié)果將變?yōu)?"55"(原始的字符串值),因為另一個運算數(shù)也會被轉(zhuǎn)換為字符串。

注意:為了避免 JavaScript 中的一種常見錯誤,在使用加法運算符時,一定要仔細檢查運算數(shù)的數(shù)據(jù)類型
??

4.4 ECMAScript 減法運算符(-)

減法運算符(-),也是一個常用的運算符:

var iResult = 2 - 1;

減、乘和除沒有加法特殊,都是一個性質(zhì),這里我們就多帶帶解讀減法運算符(-)

我們還是先看看ECMAScript5規(guī)范(熟讀規(guī)范,你會學到很多很多)對減號運算符 ( - )解讀,我們翻到11.6.2。

與加法運算符一樣,在處理特殊值時,減法運算符也有一些特殊行為:

某個運算數(shù)是 NaN,那么結(jié)果為 NaN。

Infinity 減 Infinity,結(jié)果為 NaN。

-Infinity 減 -Infinity,結(jié)果為 NaN。

Infinity 減 -Infinity,結(jié)果為 Infinity。

-Infinity 減 Infinity,結(jié)果為 -Infinity。

+0 減 +0,結(jié)果為 +0。

-0 減 -0,結(jié)果為 -0。

+0 減 -0,結(jié)果為 +0。

某個運算符不是數(shù)字,那么結(jié)果為 NaN。

注釋:如果運算數(shù)都是數(shù)字,那么執(zhí)行常規(guī)的減法運算,并返回結(jié)果。

??

4.5 ECMAScript 前自增運算符(++)

直接從 C(和 Java)借用的兩個運算符是前增量運算符和前減量運算符。
所謂前增量運算符,就是數(shù)值上加 1,形式是在變量前放兩個加號(++):

var iNum = 10;
++iNum;

第二行代碼把 iNum 增加到了 11,它實質(zhì)上等價于:

var iNum = 10;
iNum = iNum + 1;

我們還是先看看ECMAScript5規(guī)范(熟讀規(guī)范,你會學到很多很多)對前自增運算符 ( ++ )解讀,我們翻到11.4.4。

此圖有坑,后面會說到,坑了我很久。。。

看不懂這些抽象函數(shù)和詞匯也不要緊,想要深入了解可以通讀ECMAScript5規(guī)范中文版,看幾遍就熟悉了,第一次看見這些肯定一臉懵逼,這是什么玩意,我們只要明白++是干什么就行,這里不必去深究v8引擎怎么實現(xiàn)這個規(guī)范的。
至于

var a=1;
console.log(a++);//1
var b=1;
cosole.log(++b);//2

還弄不明白的該好好補習了,這里不在本文的知識點,也不去花篇幅講解這些,這里我們只要明白一點: 所謂前增量運算符,就是數(shù)值上加 1 。
??

4.6 ECMAScript 自動分號(;)插入

盡管 JavaScript 有 C 的代碼風格,但是它不強制要求在代碼中使用分號,實際上可以省略它們。

JavaScript 不是一個沒有分號的語言,恰恰相反上它需要分號來就解析源代碼。 因此 JavaScript 解析器在遇到由于缺少分號導(dǎo)致的解析錯誤時,會自動在源代碼中插入分號。

4.6.1例子
var foo = function() {
} // 解析錯誤,分號丟失
test()

自動插入分號,解析器重新解析。

var foo = function() {
}; // 沒有錯誤,解析繼續(xù)
test()
4.6.2工作原理

下面的代碼沒有分號,因此解析器需要自己判斷需要在哪些地方插入分號。

(function(window, undefined) {
    function test(options) {
        log("testing!")

        (options.list || []).forEach(function(i) {

        })

        options.value.test(
            "long string to pass here",
            "and another long string to pass"
        )

        return
        {
            foo: function() {}
        }
    }
    window.test = test

})(window)

(function(window) {
    window.someLibrary = {}
})(window)

下面是解析器"猜測"的結(jié)果。

(function(window, undefined) {
    function test(options) {

        // 沒有插入分號,兩行被合并為一行
        log("testing!")(options.list || []).forEach(function(i) {

        }); // <- 插入分號

        options.value.test(
            "long string to pass here",
            "and another long string to pass"
        ); // <- 插入分號

        return; // <- 插入分號, 改變了 return 表達式的行為
        { // 作為一個代碼段處理
            foo: function() {}
        }; // <- 插入分號
    }
    window.test = test; // <- 插入分號

// 兩行又被合并了
})(window)(function(window) {
    window.someLibrary = {}; // <- 插入分號
})(window); //<- 插入分號

解析器顯著改變了上面代碼的行為,在另外一些情況下也會做出錯誤的處理。

4.6.3 ECMAScript對自動分號插入的規(guī)則

我們翻到7.9章節(jié),看看其中插入分號的機制和原理,清楚只寫以后就可以盡量以后少踩坑

必須用分號終止某些 ECMAScript 語句 ( 空語句 , 變量聲明語句 , 表達式語句 , do-while 語句 , continue 語句 , break 語句 , return 語句 ,throw 語句 )。這些分號總是明確的顯示在源文本里。然而,為了方便起見,某些情況下這些分號可以在源文本里省略。描述這種情況會說:這種情況下給源代碼的 token 流自動插入分號。??

還是比較抽象,看不太懂是不是,不要緊,我們看看實際例子,總結(jié)出幾個規(guī)律就行,我們先不看抽象的,看著頭暈,看看具體的總結(jié)說明, 化抽象為具體

首先這些規(guī)則是基于兩點:

以換行為基礎(chǔ);

解析器會盡量將新行并入當前行,當且僅當符合ASI規(guī)則時才會將新行視為獨立的語句。

4.6.3.1 ASI的規(guī)則

1. 新行并入當前行將構(gòu)成非法語句,自動插入分號。

if(1 < 10) a = 1
console.log(a)
// 等價于
if(1 < 10) a = 1;
console.log(a);

2. 在continue,return,break,throw后自動插入分號

return
{a: 1}
// 等價于
return;
{a: 1};

3. ++、--后綴表達式作為新行的開始,在行首自動插入分號

a
++
c
// 等價于
a;
++c;

4. 代碼塊的最后一個語句會自動插入分號

function(){ a = 1 }
// 等價于
function(){ a = 1; }
4.6.3.2 No ASI的規(guī)則

1. 新行以 ( 開始

var a = 1
var b = a
(a+b).toString()
// 會被解析為以a+b為入?yún)⒄{(diào)用函數(shù)a,然后調(diào)用函數(shù)返回值的toString函數(shù)
var a = 1
var b =a(a+b).toString()

2. 新行以 [ 開始

var a = ["a1", "a2"]
var b = a
[0,1].slice(1)
// 會被解析先獲取a[1],然后調(diào)用a[1].slice(1)。
// 由于逗號位于[]內(nèi),且不被解析為數(shù)組字面量,而被解析為運算符,而逗號運算符會先執(zhí)
行左側(cè)表達式,然后執(zhí)行右側(cè)表達式并且以右側(cè)表達式的計算結(jié)果作為返回值
var a = ["a1", "a2"]
var b = a[0,1].slice(1)

3. 新行以 / 開始

var a = 1
var b = a
/test/.test(b)
// /會被解析為整除運算符,而不是正則表達式字面量的起始符號。瀏覽器中會報test前多了個.號
var a = 1
var b = a / test / .test(b)

4. 新行以 + 、 - 、 % 和 * 開始

var a = 2
var b = a
+a
// 會解析如下格式
var a = 2
var b = a + a

5. 新行以 , 或 . 開始

var a = 2
var b = a
.toString()
console.log(typeof b)
// 會解析為
var a = 2
var b = a.toString()
console.log(typeof b)

到這里我們已經(jīng)對ASI的規(guī)則有一定的了解了,另外還有一樣有趣的事情,就是“空語句”。

// 三個空語句
;;;

// 只有if條件語句,語句塊為空語句。
// 可實現(xiàn)unless條件語句的效果
if(1>2);else
  console.log("2 is greater than 1 always!");

// 只有while條件語句,循環(huán)體為空語句。
var a = 1
while(++a < 100);
4.6.4 結(jié)論

建議絕對不要省略分號,同時也提倡將花括號和相應(yīng)的表達式放在一行, 對于只有一行代碼的 if 或者 else 表達式,也不應(yīng)該省略花括號。 這些良好的編程習慣不僅可以提到代碼的一致性,而且可以防止解析器改變代碼行為的錯誤處理。
?關(guān)于JavaScript 語句后應(yīng)該加分號么?(點我查看)我們可以看看知乎上大牛們對著個問題的看法。

???

4.7 ECMAScript 對{}的解讀,確切說應(yīng)該是瀏覽器對{}的解析

js引擎是如何判斷{}是代碼塊還是對象的?

這個問題不知道大家有沒有想過,先看看幾個例子吧?

首先要深入明白的概念:

4.7.1 JavaScript的語句與原始表達式

原始表達式是表達式的最小單位——它不再包含其他表達式。javascript中的原始表達式包括this關(guān)鍵字、標識符引用、字面量引用、數(shù)組初始化、對象初始化和分組表達式,復(fù)雜表達式暫不做討論。

語句沒有返回值,而表達式都有返回值的,表達式?jīng)]有設(shè)置返回值的話默認返回都是undefined。

javascript 里面滿足這個條件的就函數(shù)聲明、變量聲明(var a=10是聲明和賦值)、for語句、if語句、while語句、switch語句、return、try catch。
但是 javascript 還有一種函數(shù)表達式,它的形式跟函數(shù)聲明一模一樣。如果寫 function fn() { return 0;} 是函數(shù)聲明而寫var a = function fn(){ return 0;} 等號后面的就是函數(shù)表達式。

4.7.2 再來看看幾個例子吧
1.{a:1}
2.{a:1};
3.{a:1}+1

我們直接在chrome看看結(jié)果:

很奇怪是吧:
再來看看在Firefox下面的情況:

其他IE沒測,我Mac沒法裝IE,大家自行測試。

第二個很好理解,在有;的情況下,chrome和Firefox一致的把{a:1}解析為代碼塊,那么{a:1}怎么理解這個代碼塊,為什么不報錯,還記得goto語句嗎,JavaScript保留了goto的語法,我最先也半天沒緩過神來,還好記得c語言里面的這個語法,沒白學,其實可以這么理解:

{
a:
 1;
};

關(guān)于第二個{a:1}+1的答案,chrome和Firefox接過也一致,兩個瀏覽器都會把這段代碼解析成:

{
a:
 1;
};
+1;

其中關(guān)于{a:1}兩個瀏覽器就達成了不一樣的意見,只要{}前面沒有任何運算符號,F(xiàn)irefox始終如一的把{}解析成{};也就是我們熟知的代碼塊,而不是對象字面量。

而chrome就不同了,如果{a:1}后面和前面啥也沒有,{a:1}在chrome瀏覽器會首先檢查這個是不是標準對象格式,如果是返回這個對象,如果不是,則當做代碼塊執(zhí)行代碼。當然這種情況基本可以不考慮,你寫代碼就寫個{a:1}然后就完了?

共同的特點:

當{}的前面有運算符號的時候,+,-,*,/,()等等,{}都會被解析成對象字面量,這無可爭議。

當{}前面沒有運算符時候但有;結(jié)尾的時候,或者瀏覽器的自動分號插入機制給{}后面插入分號(;)時候,此時{}都會被解析成代碼塊。

如果{}前面什么運算符都沒有,{}后面也沒有分號(;)結(jié)尾,F(xiàn)irefox會始終如一的解析為代碼塊,而chrome有細微的差別,chrome會解析為對象字面量。

這里也是我通過瀏覽器輸出結(jié)果進行的一種歸納,當然可能還有沒有總結(jié)到位的地方,也可能還有錯誤,發(fā)現(xiàn)ECMAScript規(guī)范對于{}何時解析為對象何時解析為代碼塊也沒有找到比較詳細的解答,有可能也是我看的不仔細,遺漏了這塊,還望大家能解答一下這塊。

4.8 小結(jié)

如果你覺得以上的很繁瑣,我是新手,也看不太懂,不要緊,不要慌,循序漸進,以后會懂的,這里我就直接總結(jié)出幾個結(jié)論,總結(jié)的不對的地方,還望反饋指出,對照著結(jié)論來驗證上面的十幾個例子:

數(shù)組下標([])優(yōu)先級最高, 一元運算符(--,++,+,-)的優(yōu)先級高于加法或減法運算符(+,-);

++前增量運算符,就是數(shù)值上加 1;

一元運算符(+,-)的后面如果不是數(shù)字,會調(diào)用 ToNumber 方法按照規(guī)則轉(zhuǎn)化成數(shù)字類型。

對于加號運算符(+)

首先執(zhí)行代碼,調(diào)用 **ToPrimitive** 方法得到原始值

①如果原始值是兩個數(shù)字,則直接相加得出結(jié)果。

②如果兩個原始值都是字符串,把第二個字符串連接到第一個上,也就是相當于調(diào)用 concat 方法。
③如果只有一個原始值是字符串,調(diào)用 ToString 方法把另一個運算數(shù)轉(zhuǎn)換成字符串,結(jié)果是兩個字符串連接成的字符串。

對于減號運算符(-)

不知道大家有沒有看到[ECMAScript](http://yanhaijing.com/es5/#about)規(guī)范,這里比+少了一步 **ToPrimitive**  ,所以 **-** 相對容易理解。

①如果是兩個數(shù)字,則直接相減得出結(jié)果。

②如果有一個不是數(shù)字,會調(diào)用 ToNumber 方法按照規(guī)則轉(zhuǎn)化成數(shù)字類型,然后進行相減。

分號的插入

①新行并入當前行將構(gòu)成非法語句,自動插入分號。
②在continue,return,break,throw后自動插入分號
③++、--后綴表達式作為新行的開始,在行首自動插入分號
④代碼塊的最后一個語句會自動插入分號
⑤新行以 ( 、[、、+ 、 - 、,、. % 和 *開始都不會插入分號

{}的兩種解讀

①當{}的前面有運算符號的時候,+,-,*,/,()等等,{}都會被解析成對象字面量,這無可爭議。
②當{}前面沒有運算符時候但有;結(jié)尾的時候,或者瀏覽器的自動分號插入機制給{}后面插入分號(;)時候,此時{}都會被解析成代碼塊。
③如果{}前面什么運算符都沒有,{}后面也沒有分號(;)結(jié)尾,F(xiàn)irefox會始終如一的解析為代碼塊,而chrome有細微的差別,chrome會解析為對象字面量。

???

五、ECMAScript的規(guī)范定義的抽象操作

前面關(guān)于ECMAScript規(guī)范的解讀,涉及到幾個重要的抽象操作:

GetValue(v) : 引用規(guī)范類型

Type(x) : 獲取x的類型

ToNumber(x) : 將x轉(zhuǎn)換為Number類型

ToString(x) : 將x轉(zhuǎn)換為String類型

SameValue(x,y) : 計算非數(shù)字類型x,y是否相同

ToPrimitive(x) : 將x轉(zhuǎn)換為原始值

?

5.1 原始值

首先,讓我們快速的復(fù)習一下。 在 JavaScript 中,一共有兩種類型的值(ES6的 symbol 暫不做討論):

原始值(primitives)

1. undefined
2. null
3. boolean
4. number
5. string

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

?

5.2 GetValue(v)

這里的每個操作都有其嚴格并復(fù)雜的定義,可以直接查閱ECMA規(guī)范文檔對其的詳細說明。
附上在線中文文檔地址:ECMAScript

我們先看看GetValue(v) : 引用規(guī)范類型,下面是ECMAScript規(guī)范的解讀:

這什么鬼,我也不太懂,反正就是關(guān)于引用規(guī)范的一些抽象描述,鄙人才疏學淺,也不能化抽象為具體的解釋一番,太抽象了,好難啊,功力還不夠,不懂但對我們解決上面的問題也沒有什么影響,我們只看關(guān)鍵的幾個:

這里我們先看下SameValue()和ToPrimitive()兩個操作。
??

5.3 SameValue(x,y)

我們還是先看看ECMAScript5規(guī)范(熟讀規(guī)范,你會學到很多很多)對 SameValue 方法解讀,我們翻到9.12。

這個SameValue操作說的就是,如果x,y兩個值類型相同,但又不同時是Number類型時的比較是否相等的操作。
??

5.4 ToPrimitive(input [ , PreferredType])

ToPrimitive() 方法
轉(zhuǎn)換成原始類型方法。

還是來看看 ECMAScript 標準怎么定義 ToPrimitice 方法的:

是不是看了這個定義,還是一臉懵逼,ToPrimitive這尼瑪什么玩意啊?這不是等于沒說嗎?

再來看看火狐MDN上面文檔的介紹:
JS::ToPrimitive

查了一下資料,上面要說的可以概括成:

ToPrimitive(obj,preferredType)

JS引擎內(nèi)部轉(zhuǎn)換為原始值ToPrimitive(obj,preferredType)函數(shù)接受兩個參數(shù),第一個obj為被轉(zhuǎn)換的對象,第二個
preferredType為希望轉(zhuǎn)換成的類型(默認為空,接受的值為Number或String)

在執(zhí)行ToPrimitive(obj,preferredType)時如果第二個參數(shù)為空并且obj為Date的事例時,此時preferredType會
被設(shè)置為String,其他情況下preferredType都會被設(shè)置為Number如果preferredType為Number,ToPrimitive執(zhí)
行過程如
下:
1. 如果obj為原始值,直接返回;
2. 否則調(diào)用 obj.valueOf(),如果執(zhí)行結(jié)果是原始值,返回之;
3. 否則調(diào)用 obj.toString(),如果執(zhí)行結(jié)果是原始值,返回之;
4. 否則拋異常。

如果preferredType為String,將上面的第2步和第3步調(diào)換,即:
1. 如果obj為原始值,直接返回;
2. 否則調(diào)用 obj.toString(),如果執(zhí)行結(jié)果是原始值,返回之;
3. 否則調(diào)用 obj.valueOf(),如果執(zhí)行結(jié)果是原始值,返回之;
4. 否則拋異常。

首先我們要明白 obj.valueOf()obj.toString() 還有原始值分別是什么意思,這是弄懂上面描述的前提之一:

toString用來返回對象的字符串表示。

var obj = {};
console.log(obj.toString());//[object Object]

var arr2 = [];
console.log(arr2.toString());//""空字符串

var date = new Date();
console.log(date.toString());//Sun Feb 28 2016 13:40:36 GMT+0800 (中國標準時間)

valueOf方法返回對象的原始值,可能是字符串、數(shù)值或bool值等,看具體的對象。

var obj = {
  name: "obj"
};
console.log(obj.valueOf());//Object {name: "obj"}

var arr1 = [1];
console.log(arr1.valueOf());//[1]



var date = new Date();
console.log(date.valueOf());//1456638436303
如代碼所示,三個不同的對象實例調(diào)用valueOf返回不同的數(shù)據(jù)

原始值指的是["Null","Undefined","String","Boolean","Number"]五種基本數(shù)據(jù)類型之一,一開始就提到過。

弄清楚這些以后,舉個簡單的例子:

var a={};
ToPrimitive(a)

分析:a是對象類型但不是Date實例對象,所以preferredType默認是Number,先調(diào)用a.valueOf()不是原始值,繼續(xù)來調(diào)
用a.toString()得到string字符串,此時為原始值,返回之.所以最后ToPrimitive(a)得到就是"[object Object]".

如果覺得描述還不好明白,一大堆描述晦澀又難懂,我們用代碼說話:

const toPrimitive = (obj, preferredType="Number") => {
    let Utils = {
        typeOf: function(obj) {
            return Object.prototype.toString.call(obj).slice(8, -1);
        },
        isPrimitive: function(obj) {
            let types = ["Null", "String", "Boolean", "Undefined", "Number"];
            return types.indexOf(this.typeOf(obj)) !== -1;
        }
    };

    if (Utils.isPrimitive(obj)) {
        return obj;
    }

    preferredType = (preferredType === "String" || Utils.typeOf(obj) === "Date") ?
     "String" : "Number";

    if (preferredType === "Number") {
        if (Utils.isPrimitive(obj.valueOf())) {
            return obj.valueOf()
        };
        if (Utils.isPrimitive(obj.toString())) {
            return obj.toString()
        };
    } else {
        if (Utils.isPrimitive(obj.toString())) {
            return obj.toString()
        };
        if (Utils.isPrimitive(obj.valueOf())) {
            return obj.valueOf()
        };
    }
}

var a={};
ToPrimitive(a);//"[object Object]",與上面文字分析的一致

??

5.5 ToNumber(x)

這個就比ToPrimitive() 方法好理解多了,就是把其他類型按照一定的規(guī)則轉(zhuǎn)化成數(shù)字類型,也就是類似Number()和parseInt()的方法。

還是繼續(xù)看看ECMAScipt規(guī)范中對于Number的轉(zhuǎn)換

??是不是又看到 ToPrimitive() 方法了,是不是看了上面的就好理解多了,如果ToNumber(x)這個x是對象就要調(diào)用ToPrimitive方法返回x的原始值,是不是一下子就串起來了。

??

5.6 ToString(x)

這個理解起來跟 ToNumber 方法大同小異,還是繼續(xù)看看ECMAScipt規(guī)范中對于String的轉(zhuǎn)換.

對數(shù)值類型應(yīng)用 ToString
ToString 運算符將數(shù)字 m 轉(zhuǎn)換為字符串格式的給出如下所示:

如果 m 是 NaN,返回字符串 "NaN"。

如果 m 是 +0 或 -0,返回字符串 "0"。

如果 m 小于零,返回連接 "-" 和 ToString (-m) 的字符串。

如果 m 無限大,返回字符串 "Infinity"。

否則,令 n, k, 和 s 是整數(shù),使得 k ≥ 1, 10k-1 ≤ s < 10k,s × 10n-k 的數(shù)字值是 m,且 k 足夠小。要注意的是,k 是 s 在十進制表示中的數(shù)字的個數(shù)。s 不被 10 整除,且s 的至少要求的有效數(shù)字位數(shù)不一定要被這些標準唯一確定。

如果 k ≤ n ≤ 21,返回由 k 個 s 在十進制表示中的數(shù)字組成的字符串(有序的,開頭沒有零),后面跟隨字符 "0" 的 n-k 次出現(xiàn)。

如果 0 < n ≤ 21,返回由 s 在十進制表示中的、最多 n 個有效數(shù)字組成的字符串,后面跟隨一個小數(shù)點 ". ",再后面是余下的 k-n 個 s 在十進制表示中的數(shù)字。

如果 -6 < n ≤ 0,返回由字符 "0" 組成的字符串,后面跟隨一個小數(shù)點 ". ",再后面是字符 "0" 的 -n 次出現(xiàn),再往后是 k 個 s 在十進制表示中的數(shù)字。

否則,如果 k = 1,返回由單個數(shù)字 s 組成的字符串,后面跟隨小寫字母 "e",根據(jù) n-1 是正或負,再后面是一個加號 "+" 或減號 "-" ,再往后是整數(shù) abs(n-1) 的十進制表示(沒有前置的零)。

返回由 s 在十進制表示中的、最多的有效數(shù)字組成的字符串,后面跟隨一個小數(shù)點 ". ",再后面是余下的是 k-1 個 s 在十進制表示中的數(shù)字,再往后是小寫字母 "e",根據(jù)n-1 是正或負,再后面是一個加號 "+ " 或減號 "-" ,再往后是整數(shù) abs(n-1) 的十進制表示(沒有前置的零)。

???

六、驗證分析++[[]][+[]]+[+[]]==10?

養(yǎng)兵千日,用兵一時。

了解了這么多深入的基礎(chǔ)知識,該發(fā)揮用武之地了,我已經(jīng)用完洪荒之力了,是時候表演真正的技術(shù)了。

好像前面忘記講 == 符號了,不要緊,之前這個我的上一篇博文已經(jīng)非常詳細的分析過了,可以看看我的這篇博文(點擊查看)。這里就不花篇幅介紹了,感覺越來越坑,越寫越多。

這里就簡單說一下,總結(jié)一下==轉(zhuǎn)換規(guī)則:

==運算規(guī)則的圖形化表示

1. undefined == null,結(jié)果是true。且它倆與所有其他值比較的結(jié)果都是false。

2. String == Boolean,需要兩個操作數(shù)同時轉(zhuǎn)為Number。

3. String/Boolean == Number,需要String/Boolean轉(zhuǎn)為Number。

4. Object == Primitive,需要Object轉(zhuǎn)為Primitive(具體通過valueOf和toString方法)。

瞧見沒有,一共只有4條規(guī)則!是不是很清晰、很簡單。
1.首先++[[]][+[]]+[+[]]首先拆分一下:

根據(jù) 4.1 ECMAScript 運算符優(yōu)先級 可以這樣拆分:
相當于這樣:

(++[[]][+[]])
+
([+[]])
2.先來分析右邊的[+[]]

①先看里面的+[]

根據(jù) 4.2 ECMAScript 一元運算符(+、-) 可以知道,一元運算符會調(diào)用 ToNumber 方法把 ToNumber([]) 轉(zhuǎn)化成數(shù)字。

根據(jù) 5.5 ToNumber(x) 的轉(zhuǎn)換規(guī)則,x為[]是數(shù)組對象,因此會調(diào)用 ToPrimitive 方法。

根據(jù) 5.4 ToPrimitive(input [ , PreferredType]) 的轉(zhuǎn)換規(guī)則,空數(shù)組先調(diào)用 valueOf() 方法,得到[]不是原始值,繼續(xù)調(diào)用 toString() 方法,得到 ""空字符串 。

遞歸的調(diào)用之后成了 ToNumber("") ,答案顯而易見,根據(jù) 5.5 ToNumber(x) 的轉(zhuǎn)換規(guī)則對照圖片可以看出ToNumber("")===0。 那么[+[]]就變相的成了[0] 。

此時成了(++[[]][+[]])+[0]

3.再來分析左邊邊的++[[]][+[]]

+[]上面已經(jīng)分析出來了,結(jié)果為0,那么此時就成了++[[]][0]

根據(jù) 4.2 ECMAScript 一元運算符(+、-) 可以知道,數(shù)組下標的優(yōu)先級高于一元運算符++,那么理所當然成了這樣 ++([[]][0]) ,而[[]][0]可以看出數(shù)組下標為0也就是第一個元素,此時為[],那么最后成了++[].

++[]這是什么鬼?,根據(jù) 4.5 ECMAScript 前自增運算符(++) 沒有發(fā)現(xiàn)任何有調(diào)用 ToNumber 的方法,瀏覽器試了一下,果然有問題,報錯啦,到底哪里出問題了呢,為什么走著走著就走偏了。問題出在哪一步呢?

4.分析問題錯誤的原因

為什么++([[]][0])在瀏覽器不報錯,而++[]報錯,我知道問題就出在這一步,但是一直相不出原因,光瞎想是沒用的,沒事繼續(xù)讀讀ECMAScript規(guī)范,然后中文版的并沒有看出什么玩意,最后在github英文版找到原因了。

首先我們在瀏覽器輸出一下++[]

無意之中照著錯誤搜,搜到了這個后綴自增++:

順便看看大同小異的前綴自增++

Increment Operator_操作的第5步PutValue(expr, newValue)要求expr是引用。這就是問題的關(guān)鍵,為什么之前我沒發(fā)現(xiàn),因為之前我一直看的是中文版,來看看中文版的截圖對比一下

發(fā)現(xiàn)后面的3,4,5都沒有,我一度以為自己理解錯了,為什么這個規(guī)則沒有調(diào)ToNumber()卻也能得到數(shù)字,原來是翻譯中這塊內(nèi)容遺漏了,我該好好補習英語了,盡量多看英文文檔。

看到第五條大大的 Call PutValue(expr, newValue). ,

閱讀es5英文文檔,可以看到_Prefix Increment Operator_操作的第5步PutValue(expr, newValue)要求expr是引用。

我們還是來看看 PutValue 到底是什么定義,這里我們只需要知道++a,這個a是引用類型才不會報Uncaught ReferenceError: Invalid left-hand side expression in postfix operation這個錯誤。

而我們知道[[]][0]是對象的屬性訪問,而我們知道對象的屬性訪問返回的是引用,所以可以正確執(zhí)行。
??

5.進一步拆分

++[[]][0]可以這么拆分,只要保持引用關(guān)系就行:

var refence=[[]][0];
++refence;

再來進一步拆分

var refence=[];
refence=refence+1;

最后就成了

refence=[]+1;

根據(jù) 4.3 ECMAScript 加法運算符(+) ,[]+1可以看成是ToPrimitive([])+ToPrimitive(1),根據(jù) 5.4 ToPrimitive(input [ , PreferredType]) 的轉(zhuǎn)換規(guī)則,空數(shù)組先調(diào)用 valueOf() 方法,得到[]不是原始值,繼續(xù)調(diào)用 toString() 方法,得到 "" 空字符串。

于是就成了 ""+1 ,根據(jù) 4.3 ECMAScript 加法運算符(+) ,有一個字符串,另外一個也會變成字符串,所以""+1==="1"。所以 ++[[]][0] === "1" ;

好像分析的是這么回事,其實錯了,大家不要跟著我錯誤的步驟走,我其實忽略了很重要的一點。

看看規(guī)范有一點遺漏了,就是 Let oldValue be ToNumber(GetValue(expr)).

就是++時候舊的值要進行 ToNumber() 運算,最后最后一步應(yīng)該是這樣子的:

refence=ToNumber([])+1;

ToNumber([])===0,別問我為什么,照著我上面的分析自己分析一遍,不難,我因為分析多了,所以一眼就看出來了,所以最后成了0+1=1的問題,所以 ++[[]][0] === 1 。
??

6. 謎底揭開?

左邊++[[]][0] === 1;
右邊[+[]]的值為[0];
所以最后成了1+[0]的問題了。
根據(jù) 5.4 ToPrimitive(input [ , PreferredType]) 的轉(zhuǎn)換規(guī)則,[0]數(shù)組先調(diào)用 valueOf() 方法,得到[0]不是原始值,繼續(xù)調(diào)用 toString() 方法,得到 “0” 的字符串。

所以最后就成了 1+"0"==="10" 。

7.最后的最后

于是最后就成了 "10" == 10 的問題,根據(jù)ECMAScript規(guī)范==的對應(yīng)法則:

對比第5條,可以發(fā)現(xiàn)最后成了ToNumber("10")與10的比較,而ToNumber("10") === 10,
左邊最后 === 10,
右邊最后 === 10。
10 === 10為true.

所以 ++[[]][+[]]+[+[]]==10 為true,大功告成,可喜可賀,實力分析了一波,有錯誤還望批評指正。

??

七、我的疑惑
1. {}+{}//chrome:"[object Object][object Object]",F(xiàn)irfox:NaN

2. {}+[]//0

3. []+{}//"[object Object]"

通過這個例子,我發(fā)現(xiàn)剛才4.7 ECMAScript 對{}的解讀還不夠徹底,首先我們按照前面常規(guī)的思維來解答:

1.第一種思維:第一個{}解析為對面字面量

第一例子: {}+{} 首先左邊{}和右邊{}會調(diào)用 ToPrimitive 兩邊都會得到:"[object Object]",所以最后就是這兩個相同的字符串相加,得到: "object Object" ,chrome符合,F(xiàn)irefox不符合。

第二個例子: {}+[] 按照這種思維首先左邊{}和右邊[]會調(diào)用 ToPrimitive ,分別得到"[object Object]"和""空字符串,那么相加結(jié)果應(yīng)該是 "[object Object]" ,為什么結(jié)果成了 0 ,而且在 chromeFirfox 都是0?

第三個例子: []+{} 按照這種思維首先左邊[]和右邊{}會調(diào)用 ToPrimitive ,分別得到""空字符串和"[object Object]",最后相加結(jié)果 "[object Object]" ,這個沒有任何疑惑,chrome和Firefox都符合。

2.第一種思維:第一個{}解析為代碼塊

第一例子: {}+{} 瀏覽器這么解析,把{}不解析為對象字面量而是代碼塊,也就是let a={}這種塊,代碼可以看成是這樣 {};+{} ,那么{};執(zhí)行啥也沒有,接下來就是 +{} ,+是一元運算符,上面講到了,這里+{}執(zhí)行時候首先會調(diào)用ToNumber(),參數(shù){}是object會首先調(diào)用 ToPrimitive 得到原始值: "[object Object]" ,這時候就可以發(fā)現(xiàn)ToNumber("[object Object]")轉(zhuǎn)化的就是 NaN 了,chrome不符合,F(xiàn)irefox符合。

第二個例子: {}+[] 按照這種思維,最后解析成 {};+[] ,+是一元運算符,上面講到了,這里+[]執(zhí)行時候首先會調(diào)用ToNumber(),參數(shù)[]是object會首先調(diào)用 ToPrimitive 得到原始值: ""空字符串 ,最后根據(jù)規(guī)則ToNumber("")得到數(shù)字0.這種思維下沒有任何疑惑,chrome和Firefox都符合。

第三個例子: []+{} 首先左邊[]和右邊{}會調(diào)用 ToPrimitive ,分別得到""空字符串和"[object Object]",最后相加結(jié)果 "[object Object]" ,這個沒有任何疑惑,chrome和Firefox都符合。

?那么問題來了?問題的矛盾就在于第一條和第二條,chrome和Firefox對于{}+{}解析是不一樣的,對于第一個{}chrome解析為對象字面量,而Firefox解析為代碼塊,這無可厚非, 關(guān)鍵是第二個例子{}+[] ,既然第一個例子 {}+{} 的第一個{}chrome解析為對象字面量而第二個例子 {}+[] 中,chrome卻解析為代碼塊,匪夷所思,有誰能扒一扒源碼分析一下,chrome對{}的詳細解析,到底什么時候解析為代碼塊,什么時候解析為對象字面量?有點想不明白為什么這么不一致,而 Firefox始終如一,第一個{}一直解析為代碼塊,運算符號后面{}解析為對象字面量。

3.捉摸不透

Firefox的我能理解,開頭{}一律解析為代碼塊(block),而chrome卻讓人捉摸不透。。。
??

八、結(jié)束

前面的十幾個例子,大家有興趣對照著規(guī)則自己一個一個做做,看看自己是否真的理解了,理解了也再熟悉一遍,學習本來就是一個重復(fù)的過程。

突然靈機一動:

    var obj = {
        valueOf: function() {
            return 18;
        }
    };

    console.log(
            1 <= "2",
            "1" <= "a",
            obj >= "17"
    );

這個答案又是多少呢?

 var obj = {
        valueOf: function() {
            return {a:1};
        },
        toString:function(){
            return 0;
        }
    };

console.log(obj==[]);

最后這個呢?

 var obj = {
        valueOf: function() {
            return {a:1};
        },
        toString:function(){
            return "0";
        }
    };

console.log(obj==[]);

??

九、相關(guān)資料

從 []==![] 為 true 來剖析 JavaScript 各種蛋疼的類型轉(zhuǎn)換(厚顏無恥的也參考一下自己文章)
ECMAScript5.1中文版
Annotated ECMAScript 5.1
JavaScript 秘密花園
w3school中文文檔
JS魔法堂:ASI(自動分號插入機制)和前置分號
JavaScript中,{}+{}等于多少?

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

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

相關(guān)文章

  • JavaScript隱式類型轉(zhuǎn)換

    摘要:所謂裝箱轉(zhuǎn)換,正是把基本類型轉(zhuǎn)換為對應(yīng)的對象,他是類型轉(zhuǎn)換中一種相當重要的種類。拆箱轉(zhuǎn)換在標準中,規(guī)定了函數(shù),它是對象類型到基本類型的轉(zhuǎn)換即,拆箱轉(zhuǎn)換。拆箱轉(zhuǎn)換會嘗試調(diào)用和來獲得拆箱后的基本類型。 JavaScript隱式類型轉(zhuǎn)換 基本數(shù)據(jù)類型 ECMAScript 一共定義了七種 build-in types,其中六種為 Primitive Value,Null, Undefined...

    bingo 評論0 收藏0
  • JavaScript 中隱式類型轉(zhuǎn)換

    摘要:雖然你可能很驚訝甚至可能懷疑是的但是這都是有語言自己的一個隱式類型轉(zhuǎn)換的套路?;镜碾[式類型轉(zhuǎn)換基本類型的隱式轉(zhuǎn)換這個其實我們使用的最多例如結(jié)果返回的是而不是這就是類型的隱式轉(zhuǎn)換。 基本上所有的語言都有 隱式類型轉(zhuǎn)換 ,但是對于 弱類型語言(JS) 來說 ,隱式類型轉(zhuǎn)換會比 強類型語言(Java) 帶來更大的副作用,有些行為甚至是不可思議的。雖然你可能很驚訝 ,甚至可能懷疑是 JS 的...

    txgcwm 評論0 收藏0
  • 17道面試題徹底理解 JavaScript 中的類型轉(zhuǎn)換

    摘要:隱式類型轉(zhuǎn)換通常在邏輯判斷或者有邏輯運算符時被觸發(fā)。一元加號執(zhí)行字符串的類型轉(zhuǎn)換。邏輯運算符和將值轉(zhuǎn)為型,但是會返回原始值不是。計算從表達式開始,該表達式通過方法轉(zhuǎn)換為空字符串,然后轉(zhuǎn)換為。總結(jié)查看原文關(guān)注每日一道面試題詳解 類型轉(zhuǎn)換是將值從一種類型轉(zhuǎn)換為另一種類型的過程(比如字符串轉(zhuǎn)數(shù)字,對象轉(zhuǎn)布爾值等)。任何類型不論是原始類型還是對象類型都可以進行類型轉(zhuǎn)換,JavaScript 的...

    SKYZACK 評論0 收藏0
  • 前端基礎(chǔ)進階(八):深入詳解函數(shù)的柯里化

    摘要:函數(shù)被轉(zhuǎn)化之后得到柯里化函數(shù),能夠處理的所有剩余參數(shù)。因此柯里化也被稱為部分求值。那么函數(shù)的柯里化函數(shù)則可以如下因此下面的運算方式是等價的。而這里對于函數(shù)參數(shù)的自由處理,正是柯里化的核心所在。額外知識補充無限參數(shù)的柯里化。 showImg(https://segmentfault.com/img/remote/1460000008493346); 柯里化是函數(shù)的一個比較高級的應(yīng)用,想要...

    kk_miles 評論0 收藏0
  • 深入理解JavaScript的類型轉(zhuǎn)換

    摘要:等同于等同于其他類型和布爾類型之間的比較如果是布爾類型,則返回的結(jié)果。 showImg(https://segmentfault.com/img/bVburFq?w=796&h=398); 前言 JavaScript作為一門弱類型語言,我們在每天的編寫代碼過程中,無時無刻不在應(yīng)用著值類型轉(zhuǎn)換,但是很多時候我們只是在單純的寫,并不曾停下腳步去探尋過值類型轉(zhuǎn)換的內(nèi)部轉(zhuǎn)換規(guī)則,最近通過閱讀你...

    W4n9Hu1 評論0 收藏0

發(fā)表評論

0條評論

miya

|高級講師

TA的文章

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