理解并整理 "寬松相等" 和 "嚴(yán)格相等"

寬松相等(loose equals) == 和嚴(yán)格相等(strict equals) === 都用來判斷兩個(gè)值是否“相等”莺匠,但是它們之間有一個(gè)很重要的區(qū)別纺荧,特別是在判斷條件上晴埂。

常見的誤區(qū)是“ == 檢查值是否相等痕囱, === 檢查值和類型是否相等”诞吱。聽起來蠻有道理剂陡,然而還不夠準(zhǔn)確。很多 JavaScript 的書籍和博客也是這樣來解釋的狐胎,但是很遺憾他們都錯(cuò)了鸭栖。
正確的解釋是:“ == 允許在相等比較中進(jìn)行強(qiáng)制類型轉(zhuǎn)換,而 === 不允許握巢≡稳担”

上面兩種解釋的區(qū)別:

  1. 第一種解釋(不準(zhǔn)確的版本), === 似乎比 == 做的事情更多暴浦,因?yàn)樗€要檢查值的類型溅话。
  2. 第二種解釋中 == 的工作量更大一些,因?yàn)槿绻档念愋筒煌€需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換歌焦。

但是飞几,

  1. 雖然強(qiáng)制類型轉(zhuǎn)換確實(shí)要多花點(diǎn)時(shí)間,但僅僅是微秒級(jí)(百萬分之一秒)的差別而已独撇。
  2. == 和 === 都會(huì)檢查操作數(shù)的類型屑墨。真正的區(qū)別在于操作數(shù)類型不同時(shí)它們的處理方式不同。

拓展知識(shí)點(diǎn):
1. 存在 寬松不相等(loose not-equality) != 就是 == 的相反值纷铣, 嚴(yán)格不相等 !== 同理
2. 兩個(gè)值的類型相同時(shí)卵史,則僅比較它們是否相等,不發(fā)生強(qiáng)制類型轉(zhuǎn)換搜立。此時(shí)寬松相等與嚴(yán)格相等并無區(qū)別
3. 兩個(gè)值的類型不相同時(shí)以躯,寬松相等判斷會(huì)進(jìn)行類型轉(zhuǎn)換后 再進(jìn)行判斷比較。而轉(zhuǎn)換的類型順序總結(jié)下來是:
① 若存在一個(gè)為字符串類型啄踊,另一個(gè)可直接轉(zhuǎn)換為字符串類型 進(jìn)行比較忧设;
② 若存在一個(gè)為數(shù)字類型A,另一個(gè)為非數(shù)字類型B颠通,則非數(shù)字類型B 需轉(zhuǎn)換為數(shù)字類型后再比較址晕,即 ToNumber(B) == A。
4. 判斷使用建議:

var a = "42";
// 不要這樣用蒜哀,條件判斷不成立:
if (a == true) {
// ..
}
// 也不要這樣用斩箫,條件判斷不成立:
if (a === true) {
// ..
}
// 這樣的顯式用法沒問題:
if (a) {
// ..
}
// 這樣的顯式用法更好:
if (!!a) {
// ..
}
// 這樣的顯式用法也很好:
if (Boolean( a )) {
// ..
}

建議無論什么情況下都不要使用 == true 和 == false !!
5. 對(duì)象和非對(duì)象之間的相等比較
JS 的“拆封”:即“打開”封裝對(duì)象(如 new String("abc") ),返回其中的基本數(shù)據(jù)類型值( "abc" )撵儿。
而 == 中的 ToPromitive 強(qiáng)制類型轉(zhuǎn)換也會(huì)發(fā)生這樣的情況:先將對(duì)象類型的數(shù)據(jù) 調(diào)用 ToPromitive 抽象操作乘客,取出對(duì)象中 valueOf() 的返回值,再根據(jù)實(shí)際需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換后 進(jìn)行比較淀歇。

e.g.
var a = "abc";
var b = Object( a ); // 和new String( a )一樣
a === b; // false
a == b; // true

a == b 結(jié)果為 true 易核,因?yàn)?b 通過 ToPromitive 進(jìn)行強(qiáng)制類型轉(zhuǎn)換(也稱為“拆封”,英文為 unboxed 或者 unwrapped)浪默,并返回標(biāo)量基本類型值 "abc" , 與 a 相等.

PS:
? NaN 不等于 NaN ( JS 數(shù)據(jù)類型中 唯一跟自身不相等的類型)
? +0 等于 -0
但是牡直,也有一些值不這樣,原因是 == 算法中其他優(yōu)先級(jí)更高的規(guī)則纳决。

e.g.:
var a = null;
var b = Object( a ); // 和Object()一樣
a == b; // false
var c = undefined;
var d = Object( c ); // 和Object()一樣
c == d; // false
var e = NaN;
var f = Object( e ); // 和new Number( e )一樣
e == f; // false

因?yàn)闆]有對(duì)應(yīng)的封裝對(duì)象碰逸,所以 null 和 undefined 不能夠被封裝(boxed), Object(null) 和 Object() 均返回一個(gè)常規(guī)對(duì)象阔加。NaN 能夠被封裝為數(shù)字封裝對(duì)象饵史,但拆封之后 NaN == NaN 返回 false ,因?yàn)?NaN 不等于 N
6. 寬松相等比較 需要特別注意的 情況
① null 和 undefined 之間的相等比較
需要注意到 在 == 中 null 和 undefined 相等(它們也與其自身相等)胜榔,除此之外其他值都不存在這種相等的情況 !!

e.g.
var a = null;
var b;
a == b; // true
a == null; // true
b == null; // true
a == false; // false
b == false; // false
a == ""; // false
b == ""; // false
a == 0; // false
b == 0; // false

② 下面羅列了比較特別的判斷情況胳喷,需要注意標(biāo)注 暈 的數(shù)據(jù)

"0" == null; // false
"0" == undefined; // false
"0" == false; // true -- 暈!
"0" == NaN; // false
"0" == 0; // true
"0" == ""; // false
false == null; // false
false == undefined; // false
false == NaN; // false
false == 0; // true -- 暈夭织!
false == ""; // true -- 暈吭露!
false == []; // true -- 暈!
false == {}; // false
"" == null; // false
"" == undefined; // false
"" == NaN; // false
"" == 0; // true -- 暈尊惰!
"" == []; // true -- 暈讲竿!
"" == {}; // false
0 == null; // false
0 == undefined; // false
0 == NaN; // false
0 == []; // true -- 暈!
0 == {}; // false


e.g.1: [] == ![] // true
上面例子里 弄屡!運(yùn)算符做的操作是:根據(jù) ToBoolean 規(guī)則戴卜,它會(huì)進(jìn)行布爾值的顯式強(qiáng)制類型轉(zhuǎn)換(同時(shí)反轉(zhuǎn)奇偶校驗(yàn)位)。所以 [] == ![] 變成了 [] == false 琢岩。前
面我們講過 false == [] 投剥,最后的結(jié)果就順理成章了.

e.g.2:
2 == [2]; // true
"" == [null]; // true
上面例子中,== 右邊的值 [2] 和 [null] 會(huì)進(jìn)行 ToPrimitive 強(qiáng)制類型轉(zhuǎn)換担孔,以便能夠和左邊的基本類型值( 2 和 "" )進(jìn)行比較江锨。因?yàn)閿?shù)組的 valueOf() 返回?cái)?shù)組本身,
所以強(qiáng)制類型轉(zhuǎn)換過程中數(shù)組會(huì)進(jìn)行字符串化糕篇。
第一行中的 [2] 會(huì)轉(zhuǎn)換為 "2" 啄育,然后通過 ToNumber 轉(zhuǎn)換為 2 。
第二行中的 [null] 會(huì)直接轉(zhuǎn)換為 "" 拌消。
所以最后的結(jié)果就是 2 == 2 和 "" == "" 挑豌。

e.g.3:
0 == "\n"; // true
"" 、 "\n" (或者 " " 等其他空格組合)等空字符串被 ToNumber 強(qiáng)制類型轉(zhuǎn)換為 0 ,故上面例子的比較結(jié)果為true.

④ 整理上面內(nèi)容氓英,
建議無論什么情況下都不要使用 == true 和 == false 做為判斷 !!侯勉, 如下

"0" == false; // true -- 暈!
false == 0; // true -- 暈铝阐!
false == ""; // true -- 暈址貌!
false == []; // true -- 暈!
"" == 0; // true -- 暈徘键!
"" == []; // true -- 暈练对!
0 == []; // true -- 暈
寬松判斷時(shí),注意避免 值為 “ ”吹害、[]螟凭、0 的情況, 如下

"" == 0; // true -- 暈它呀!
"" == []; // true -- 暈赂摆!
0 == []; // true -- 暈!

日常寫的方法函數(shù)中钟些,需要注意

function doSomething(a) {
    if (a == "") {
        // ..
    }
}

如果碰到 doSomething(0) 和 doSomething([]) 這樣的情況烟号,會(huì)造成函數(shù)內(nèi)判斷相等而導(dǎo)致報(bào)錯(cuò)。

故保持兩個(gè)原則:
? 如果兩邊的值中有 true 或者 false 政恍,千萬不要使用 == 汪拥。
? 如果兩邊的值中有 [] 、 "" 或者 0 篙耗,盡量不要使用 == 迫筑。
這時(shí)最好用 === 來避免不經(jīng)意的強(qiáng)制類型轉(zhuǎn)換。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末宗弯,一起剝皮案震驚了整個(gè)濱河市脯燃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蒙保,老刑警劉巖辕棚,帶你破解...
    沈念sama閱讀 212,599評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異邓厕,居然都是意外死亡逝嚎,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門详恼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來补君,“玉大人,你說我怎么就攤上這事昧互⊥焯” “怎么了伟桅?”我有些...
    開封第一講書人閱讀 158,084評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)叽掘。 經(jīng)常有香客問我楣铁,道長(zhǎng),這世上最難降的妖魔是什么够掠? 我笑而不...
    開封第一講書人閱讀 56,708評(píng)論 1 284
  • 正文 為了忘掉前任民褂,我火速辦了婚禮茄菊,結(jié)果婚禮上疯潭,老公的妹妹穿的比我還像新娘。我一直安慰自己面殖,他們只是感情好竖哩,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,813評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著脊僚,像睡著了一般相叁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辽幌,一...
    開封第一講書人閱讀 50,021評(píng)論 1 291
  • 那天增淹,我揣著相機(jī)與錄音,去河邊找鬼乌企。 笑死虑润,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的加酵。 我是一名探鬼主播拳喻,決...
    沈念sama閱讀 39,120評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼猪腕!你這毒婦竟也來了冗澈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,866評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤陋葡,失蹤者是張志新(化名)和其女友劉穎亚亲,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體腐缤,經(jīng)...
    沈念sama閱讀 44,308評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡朵栖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,633評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了柴梆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片陨溅。...
    茶點(diǎn)故事閱讀 38,768評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖绍在,靈堂內(nèi)的尸體忽然破棺而出门扇,到底是詐尸還是另有隱情雹有,我是刑警寧澤,帶...
    沈念sama閱讀 34,461評(píng)論 4 333
  • 正文 年R本政府宣布臼寄,位于F島的核電站霸奕,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏吉拳。R本人自食惡果不足惜质帅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,094評(píng)論 3 317
  • 文/蒙蒙 一丑蛤、第九天 我趴在偏房一處隱蔽的房頂上張望吁系。 院中可真熱鬧,春花似錦猾浦、人聲如沸炼邀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拭宁。三九已至洛退,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間杰标,已是汗流浹背兵怯。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評(píng)論 1 267
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留腔剂,地道東北人媒区。 一個(gè)月前我還...
    沈念sama閱讀 46,571評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像桶蝎,于是被迫代替她去往敵國(guó)和親驻仅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,666評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容