很多時(shí)候我們會(huì)對(duì)某個(gè)語(yǔ)言的某個(gè)特性爭(zhēng)論不休,通常都只是因?yàn)槲覀儾恢浪窃趺磳?shí)現(xiàn)的钦讳。其實(shí)解決這個(gè)疑惑的最好的方法矿瘦,就是弄清楚 == 和 === 內(nèi)部的實(shí)現(xiàn)機(jī)制枕面。
例如 Google v8 就是開源的,只要看看里面的代碼缚去,就能知道到底是怎么一回事了潮秘。但是我相信絕大多數(shù)人都是沒有這個(gè)耐心的——我知道大家都在忙著掙錢養(yǎng)家——好吧,那咱就不看 Google v8 了易结,看看 ECMA-262 吧枕荞,里面已經(jīng)把實(shí)現(xiàn)算法描述得很清楚了,只要看懂了下面的內(nèi)容搞动,以后就再也不會(huì)有此類疑問了躏精。
1
當(dāng)然,在這里推薦一下我自己的前端群:621071874鹦肿,不管你是小白還是大牛矗烛,小編我都挺歡迎,不定期分享干貨以及各種經(jīng)典案例箩溃,包括我自己整理的一份2017最新的前端資料和零基礎(chǔ)入門教程瞭吃,同時(shí),還會(huì)定期和大家共同討論目前企業(yè)需求以及各類面試問題涣旨,歡迎初學(xué)和進(jìn)階中的小伙伴歪架。
一、嚴(yán)格相等運(yùn)算符 === 的實(shí)現(xiàn)
=== 被稱為 Strict Equals Operator霹陡,假設(shè)有表達(dá)式 a === b和蚪,則它的實(shí)際運(yùn)算過程如下
計(jì)算出表達(dá)式 a 的結(jié)果,并存入 lref 變量
將 GetValue(lref) 的結(jié)果存入 lval 變量
計(jì)算出表達(dá)式 b 的結(jié)果烹棉,并存入 rref 變量
將 GetValue(rref) 的結(jié)果存入 rval 變量
執(zhí)行 Strict Equality Comparison 算法判斷 rval === lval 并將結(jié)果直接返回
這里的 Strict Equality Comparison 算法很關(guān)鍵攒霹,假設(shè)要計(jì)算的是 x === y,則過程如下
1. 如果 Type(x) 和 Type(y) 不同浆洗,返回 false
2. 如果 Type(x) 為 Undefined剔蹋,返回 true
3. 如果 Type(x) 為 Null,返回 true
4. 如果 Type(x) 為 Number辅髓,則進(jìn)入下面的判斷邏輯
4.1. 如果 x 為 NaN,返回 false
4.2. 如果 y 為 NaN少梁,返回 false
4.3. 如果 x 的數(shù)字值和 y 相等洛口,返回 true
4.4. 如果 x 是 +0 且 y 是 -0,返回 true
4.5. 如果 x 是 -0 且 y 是 +0凯沪,返回 ture
4.6. 返回 false
5. 如果 Type(x) 為 String第焰,則當(dāng)且僅當(dāng) x 與 y 的字符序列完全相同(長(zhǎng)度相等,每個(gè)位置上的字符相同)時(shí)返回 true妨马,否則返回 false
6. 如果 Type(x) 為 Boolean挺举,則若 x 與 y 同為 true 或同為 false 時(shí)返回 true杀赢,否則返回 false
7. 如果 x 和 y 引用的是同一個(gè)對(duì)象,返回 true湘纵,否則返回 false
2
二脂崔、相等運(yùn)算符 == 的實(shí)現(xiàn)
好了,當(dāng)你明白了 === 的實(shí)現(xiàn)之后梧喷,我們?cè)賮?lái)看看 == 的實(shí)現(xiàn),比較一下他們有何不同?
== 被稱為 Equals Operator (注意看沒有 Strict 了)瓜浸,假設(shè)有表達(dá)式 a == b椅棺,則它的實(shí)際運(yùn)算過程如下
計(jì)算出表達(dá)式 a 的結(jié)果,并存入 lref 變量
將 GetValue(lref) 的結(jié)果存入 lval 變量
計(jì)算出表達(dá)式 b 的結(jié)果偿凭,并存入 rref 變量
將 GetValue(rref) 的結(jié)果存入 rval 變量
執(zhí)行 Abstract Equality Comparison 算法判斷 rval == lval 并將結(jié)果直接返回
注意产弹,其中的前 4 個(gè)步驟是和 === 完全相同的。唯獨(dú) 5 不同弯囊。對(duì)于 === 來(lái)說(shuō)痰哨,調(diào)用的是 Strict Equality Comparison 算法,但是 == 則調(diào)用的是 Abstract Equality Comparison 算法常挚。雖然僅一詞之差作谭,但是卻有質(zhì)的不同,我們下面就來(lái)看看到底它是怎么實(shí)現(xiàn)的
假設(shè)要計(jì)算的是 x == y奄毡,Abstract Equality Comparison 計(jì)算的過程如下(很冗長(zhǎng)折欠,但是每個(gè)步驟都很簡(jiǎn)單)
1. 如果 Type(x) 和 Type(y) 相同,則
1.1. 如果 Type(x) 為 Undefined吼过,返回 true
1.2. 如果 Type(x) 為 Null锐秦,返回 true
1.3. 如果 Type(x) 為 Number,則
1.3.1. 如果 x 是 NaN盗忱,返回 false
1.3.2. 如果 y 是 NaN酱床,返回 false
1.3.3. 如果 x 的數(shù)值與 y 相同,返回 true
1.3.4. 如果 x 是 +0 且 y 是 -0趟佃,返回 true
1.3.5. 如果 x 是 -0 且 y 是 +0扇谣,返回 true
1.3.6. 返回 false
1.4. 如果 Type(x) 為 String,則當(dāng)且僅當(dāng) x 與 y 的字符序列完全相同(長(zhǎng)度相等闲昭,每個(gè)位置上的字符相同)時(shí)返回 true罐寨,否則返回 false
1.5. 如果 Type(x) 為 Boolean,則若 x 與 y 同為 true 或同為 false 時(shí)返回 true序矩,否則返回 false
1.6. 如果 x 和 y 引用的是同一個(gè)對(duì)象鸯绿,返回 true,否則返回 false
2. 如果 x 是 null 且 y 是 undefined,返回 true
3. 如果 x 是 undefined 且 y 是 null瓶蝴,返回 ture
4. 如果 Type(x) 為 Number 且 Type(y) 為 String毒返,以 x == ToNumber(y) 的比較結(jié)果作為返回
5. 如果 Type(x) 為 String 且 Type(y) 為 Number,以 ToNumber(x) == y 的比較結(jié)果作為返回值
6. 如果 Type(x) 為 Boolean舷手,以 ToNumber(x) == y 的比較結(jié)果作為返回值
7. 如果 Type(y) 為 Boolean拧簸,以 x == ToNumber(y) 的比較結(jié)果作為返回值
8. 如果 Type(x) 為 String 或 Number 且 Type(y) 為 Object,以 x == ToPrimitive(y) 的比較結(jié)果作為返回值
9. 如果 Type(x) 為 Object 且 Type(y) 為 String 或 Number聚霜,以 ToPrimitive(x) == y 的比較結(jié)果作為返回值
10. 返回 false
三狡恬、總結(jié)
從上面的算法流程可以看出,a === b 是最簡(jiǎn)單的蝎宇。如果 a 和 b 的類型不同弟劲,那么一定會(huì)返回 false。而 a == b 則要靈活得多姥芥。JavaScript 會(huì)嘗試調(diào)整 a 和 b 的類型兔乞,例如若 a 為字符串 b 為數(shù)字,則將字符串先轉(zhuǎn)化為數(shù)字再與 b 比較凉唐,等等庸追。這在很多時(shí)候簡(jiǎn)化了程序員的代碼量。
一些程序員害怕 == 而提倡使用 === 的根本原因是台囱,他們不知道在 == 的內(nèi)部具體發(fā)生了什么淡溯。而這就導(dǎo)致誤用和出錯(cuò)。
很多人認(rèn)為簿训,當(dāng)我們不了解一個(gè) feature 的時(shí)候咱娶,我們就不用它就行了。這也許是一種習(xí)慣性邏輯强品。但尷尬的是你不用這個(gè) feature 沒問題膘侮,別人卻可能還是會(huì)用。為了能讀懂別人的代碼的榛,我們又必須實(shí)際上搞清楚這內(nèi)在的邏輯琼了。所以最終還是得付出這方面的學(xué)習(xí)成本。
這真是讓人尷尬的一件事夫晌。