JavaScript中的相等性判斷

Equality(==)

相等操作符比較兩個值是否相等菲语,在比較前將兩個被比較的值轉(zhuǎn)換為相同類型妄辩。在轉(zhuǎn)換后(等式的一邊或兩邊都可能被轉(zhuǎn)換),最終的比較方式等同于全等操作符 === 的比較方式山上。 相等操作符滿足交換律眼耀。

等于運(yùn)算符(==)檢查其兩個操作數(shù)是否相等,并返回Boolean結(jié)果佩憾。與嚴(yán)格相等運(yùn)算符(===)不同,它會嘗試強(qiáng)制類型轉(zhuǎn)換并且比較不同類型的操作數(shù)妄帘。

console.log(1 == 1); // true

console.log('hello' == 'hello'); // true

console.log('1' ==  1); // true

console.log(0 == false); // true

語法

x == y

描述

相等運(yùn)算符(== 和 !=)使用抽象相等比較算法比較兩個操作數(shù)楞黄。

  • 如果兩個操作數(shù)都是對象,則僅當(dāng)兩個操作數(shù)都引用同一個對象時才返回true抡驼。

  • 如果一個操作數(shù)是null鬼廓,另一個操作數(shù)是undefined,則返回true致盟。

  • 如果兩個操作數(shù)是不同類型的碎税,就會嘗試在比較之前將它們轉(zhuǎn)換為相同類型:
    當(dāng)數(shù)字與字符串進(jìn)行比較時,會嘗試將字符串轉(zhuǎn)換為數(shù)字值馏锡。
    如果操作數(shù)之一是Boolean雷蹂,則將布爾操作數(shù)轉(zhuǎn)換為1或0。
    1.如果是 true眷篇,則轉(zhuǎn)換為1萎河。
    2.如果是 false,則轉(zhuǎn)換為0。

    如果操作數(shù)之一是對象,另一個是數(shù)字或字符串箕速,會嘗試使用對象的valueOf()和toString()方法將對象轉(zhuǎn)換為原始值。

  • 如果操作數(shù)具有相同的類型秉沼,則將它們進(jìn)行如下比較:
    String:true僅當(dāng)兩個操作數(shù)具有相同順序的相同字符時才返回。
    Number:true僅當(dāng)兩個操作數(shù)具有相同的值時才返回。+0并被-0視為相同的值达舒。如果任一操作數(shù)為NaN值朋,則返回false。
    Boolean:true僅當(dāng)操作數(shù)為兩個true或兩個false時才返回true巩搏。

此運(yùn)算符與嚴(yán)格等于(===)運(yùn)算符之間最顯著的區(qū)別在于昨登,嚴(yán)格等于運(yùn)算符不嘗試類型轉(zhuǎn)換。相反贯底,嚴(yán)格相等運(yùn)算符始終將不同類型的操作數(shù)視為不同丰辣。

示例

沒有類型轉(zhuǎn)換的比較

console.log("hello" == "hello");                                  // true
console.log(0 == 0);                                              // true
console.log(1 == 1);                                              // true
console.log(+0 == -0);                                            // true
console.log(false == false);                                      // true
console.log(Number.MAX_SAFE_INTEGER == Number.MAX_SAFE_INTEGER);  // true
console.log(null == null);                                        // true
console.log(undefined == undefined);                              // true

console.log(NaN == NaN);                                          // false
console.log({} == {});                                            // false
console.log([] == []);                                            // false
console.log(Symbol() == Symbol());                                // false
console.log(Symbol(1) == Symbol(1));                              // false
console.log(newDate() == newDate());                              // false

與類型轉(zhuǎn)換比較

"1" ==  1;                         // true
1 == "1";                          // true
0 == false;                        // true
0 == null;                         // false
0 == undefined;                    // false
null == undefined;                 // true

const number1 = new Number(3);
const number2 = new Number(3);
number1 == 3;                      // true
number1 == number2;                // false


var num = 0;
var obj = new String("0");
var str = "0";
var b = false;

console.log(num == obj);        // true
console.log(num == str);        // true
console.log(obj == str);        // true
console.log(null == undefined); // true

// both false, except in rare cases
console.log(obj == null);       // true
console.log(obj == undefined);  // true

對象比較

const object1 = {"key": "value"}
const object2 = {"key": "value"};

console.log(object1 == object2) // false
console.log(object2 == object2) // true

比較字符串和String對象

請注意,使用構(gòu)造的字符串new String()是對象禽捆。如果將其中之一與字符串文字進(jìn)行比較笙什,則該String對象將被轉(zhuǎn)換為字符串文字并對其內(nèi)容進(jìn)行比較。但是胚想,如果兩個操作數(shù)都是String對象琐凭,則將它們作為對象進(jìn)行比較,并且必須引用相同的對象才能進(jìn)行比較:

const string1 = "hello";
const string2 = String("hello");
const string3 = new String("hello");
const string4 = new String("hello");

console.log(string1 == string2); // true
console.log(string1 == string3); // true
console.log(string1 == string4); // true
console.log(string2 == string3); // true
console.log(string2 == string4); // true
console.log(string3 == string4); // false
console.log(string4 == string4); // true

比較日期和字符串

const d = new Date('December 17, 1995 03:24:00');
const s = d.toString(); // for example: "Sun Dec 17 1995 03:24:00 GMT-0800 (Pacific Standard Time)"
console.log(d == s);    // true

相等操作符對于不同類型的值浊服,進(jìn)行的比較如下圖所示:

截屏2022-06-08 22.29.23.png

在上面的表格中,ToNumber(A) 嘗試在比較前將參數(shù) A 轉(zhuǎn)換為數(shù)字臼闻,這與 +A(單目運(yùn)算符+)的效果相同鸿吆。ToPrimitive(A)通過嘗試調(diào)用 A 的 A.toString() 和 A.valueOf() 方法,將參數(shù) A 轉(zhuǎn)換為原始值(Primitive)述呐。

一般而言惩淳,根據(jù) ECMAScript 規(guī)范,所有的對象都與 undefined 和 null 不相等乓搬。但是大部分瀏覽器允許非常窄的一類對象(即思犁,所有頁面中的 document.all 對象),在某些情況下进肯,充當(dāng)效仿 undefined 的角色激蹲。相等操作符就是在這樣的一個背景下。因此江掩,IsFalsy(A) 方法的值為 true 学辱,當(dāng)且僅當(dāng) A 效仿 undefined。在其他所有情況下环形,一個對象都不會等于 undefined 或 null策泣。

總結(jié):Equality(==) 相等符號的做法是:如果兩個操作數(shù)是不同類型的,就會嘗試在比較之前將它們轉(zhuǎn)換為相同類型危队;如果操作數(shù)具有相同的類型茫陆,則將它們進(jìn)行如下比較盅弛。可以看出對 NaN==NaN 的輸出是false讨盒、0==false 的輸出是true返顺、null==undefined 的輸出是true遂鹊、+0===-0 的輸出是true,并不是很嚴(yán)謹(jǐn)舟陆。

全等 Strict Equality(===)

全等操作符比較兩個值是否相等,兩個被比較的值在比較前都不進(jìn)行隱式轉(zhuǎn)換踱承。如果兩個被比較的值具有不同的類型茎活,這兩個值是不全等的。否則身辨,如果兩個被比較的值類型相同煌珊,值也相同吏饿,并且都不是 number 類型時猪落,兩個值全等。最后官疲,如果兩個值都是 number 類型,當(dāng)兩個都不是 NaN维费,并且數(shù)值相同,或是兩個值分別為 +0 和 -0 時且蓬,兩個值被認(rèn)為是全等的。

全等運(yùn)算符 (===) 會檢查它的兩個操作數(shù)是否相等冯事,并且返回一個布爾值結(jié)果。與相等運(yùn)算符不同摔笤,全等運(yùn)算符總是認(rèn)為不同類型的操作數(shù)是不同的彰触。

console.log(1 === 1); // true

console.log('hello' === 'hello'); // true

console.log('1' ===  1); // alse

console.log(0 === false); // false

語法

x === y

描述

全等運(yùn)算符(===和 !==)使用全等比較算法來比較兩個操作數(shù)。

  • 如果操作數(shù)的類型不同,則返回 false母债。
  • 如果兩個操作數(shù)都是對象迅皇,只有當(dāng)它們指向同一個對象時才返回 true搅荞。
  • 如果兩個操作數(shù)都為 null,或者兩個操作數(shù)都為 undefined茉贡,返回 true。
  • 如果兩個操作數(shù)有任意一個為 NaN愉粤,返回 false。
  • 否則怖亭,比較兩個操作數(shù)的值:
    數(shù)字類型必須擁有相同的數(shù)值。+0 和 -0 會被認(rèn)為是相同的值。
    字符串類型必須擁有相同順序的相同字符晨另。
    布爾運(yùn)算符必須同時為 true 或同時為 false。

全等運(yùn)算符與相等運(yùn)算符(==)最顯著的區(qū)別是,如果操作數(shù)的類型不同,== 運(yùn)算符會在比較之前嘗試將它們轉(zhuǎn)換為相同的類型。

示例

比較相同類型的操作數(shù)

console.log("hello" === "hello");        // true
console.log("hello" === "hello");         // false

console.log(3 === 3);                    // true
console.log(3 === 4);                    // false

console.log(true === true);              // true
console.log(true === false);             // false

console.log(null === null);              // true
console.log(undefined === undefined);    // true

console.log(NaN === NaN);                // false

console.log(+0 === -0);                  // true

比較不同類型的操作數(shù)

console.log("3" === 3);           // false

console.log(true === 1);          // false

console.log(null === undefined);  // false


var num = 0;
var obj = new String("0");
var str = "0";
var b = false;

console.log(num === obj); // false
console.log(num === str); // false
console.log(obj === str); // false
console.log(null === undefined); // false
console.log(obj === null); // false
console.log(obj === undefined); // false

比較對象

const object1 = {
  name: "hello"
}

const object2 = {
  name: "hello"
}

console.log(object1 === object2);  // false
console.log(object1 === object1);  // true

在日常中使用全等操作符幾乎總是正確的選擇战秋。對于除了數(shù)值之外的值涨岁,全等操作符使用明確的語義進(jìn)行比較:一個值只與自身全等尝哆。對于數(shù)值琐馆,全等操作符使用略加修改的語義來處理兩個特殊情況:第一個情況是谁撼,浮點(diǎn)數(shù) 0 是不分正負(fù)的屠缭。區(qū)分 +0 和 -0 在解決一些特定的數(shù)學(xué)問題時是必要的款咖,但是大部分情況下我們并不用關(guān)心砍聊。全等操作符認(rèn)為這兩個值是全等的俯树。第二個情況是,浮點(diǎn)數(shù)包含了 NaN 值,用來表示某些定義不明確的數(shù)學(xué)問題的解,例如:正無窮加負(fù)無窮菩浙。全等操作符認(rèn)為 NaN 與其他任何值都不全等,包括它自己。(等式 (x !== x) 成立的唯一情況是 x 的值為 NaN)

總結(jié):Strict equality(===) 嚴(yán)格相等符號是:先比較兩個操作數(shù)的類型,再去比較兩個操作數(shù)的值。可以看出對 NaN===NaN 的輸出是false、+0===-0 的輸出是true,雖然相對于(==)相等符號來說比較嚴(yán)格,但還是不能判斷所有的情況。

Objec.is()

Object.is() 方法判斷兩個值是否為同一個值腿时。

語法

Object.is(value1, value2);

參數(shù)

value1
被比較的第一個值格了。
value2
被比較的第二個值满败。

返回值

一個布爾值,表示兩個參數(shù)是否是同一個值算墨。

描述

Object.is() 方法判斷兩個值是否為同一個值宵荒,如果滿足以下任意條件則兩個值相等:

  • 都是 undefined
  • 都是 null
  • 都是 true 或都是 false
  • 都是相同長度、相同字符净嘀、按相同順序排列的字符串
  • 都是相同對象(意味著都是同一個對象的值引用)
  • 都是數(shù)字且
    都是 +0
    都是 -0
    都是 NaN
    都是同一個值报咳,非零且都不是 NaN

Object.is() 與 == 不同。== 運(yùn)算符在判斷相等前對兩邊的變量(如果它們不是同一類型)進(jìn)行強(qiáng)制轉(zhuǎn)換(這種行為將 "" == false 判斷為 true)挖藏,而 Object.is 不會強(qiáng)制轉(zhuǎn)換兩邊的值暑刃。

Object.is() 與 === 也不相同。差別是它們對待有符號的零和 NaN 不同膜眠,例如岩臣,=== 運(yùn)算符(也包括 == 運(yùn)算符)將數(shù)字 -0 和 +0 視為相等,而將 Number.NaNNaN 視為不相等宵膨。

示例

// Case 1: Evaluation result is the same as using === 
Object.is(25, 25);                  // true
Object.is('foo', 'foo');            // true
Object.is('foo', 'bar');            // false
Object.is(null, null);              // true
Object.is(undefined, undefined);    // true
Object.is(window, window);          // true
Object.is([], []);                  // false
var foo = { a: 1 }; 
var bar = { a: 1 }; 
Object.is(foo, foo);                // true
Object.is(foo, bar);                // false

// Case 2: Signed zero
Object.is(0, -0);                   // false
Object.is(+0, -0);                  // false
Object.is(-0, -0);                  // true
Object.is(0n, -0n);                 // true

// Case 3: NaN
Object.is(NaN, 0/0);                // true
Object.is(NaN, Number.NaN)          // true

Polyfill

ES5 可以通過下面的代碼架谎,實(shí)現(xiàn)和 Object.is() 方法一樣的效果。

if (!Object.is) {
  Object.defineProperty(Object, "is", {
    value: function (x, y) {
      // SameValue algorithm
      if (x === y) {
        // return true if x and y are not 0, OR
        // if x and y are both 0 of the same sign.
        // This checks for cases 1 and 2 above.
        return x !== 0 || 1 / x === 1 / y;
      } else {
        // return true if both x AND y evaluate to NaN.
        // The only possibility for a variable to not be strictly equal to itself
        // is when that variable evaluates to NaN (example: Number.NaN, 0/0, NaN).
        // This checks for case 3.
        return x !== x && y !== y;
      }
    }
  });
}

總結(jié):Object.is() 與 === 的判斷結(jié)果基本相同辟躏,差別是它們對待有符號的 0 和 NaN 不同谷扣;并且和 == 運(yùn)算符相比,Object.is 不會強(qiáng)制轉(zhuǎn)換兩邊的值捎琐。

如何選擇相等性判斷

ES2015中有四種相等算法:

  • 抽象(非嚴(yán)格)相等比較 (==)
  • 嚴(yán)格相等比較 (===): 用于 Array.prototype.indexOf, Array.prototype.lastIndexOf, 和 case-matching
  • 同值零: 用于 %TypedArray% 和 ArrayBuffer 構(gòu)造函數(shù)会涎、以及Map和Set操作,并將用于 ES2016/ES7 中的String.prototype.includes
  • 同值: 用于所有其他地方

JavaScript提供三種不同的值比較操作:

  • 嚴(yán)格相等比較 (也被稱作"strict equality", "identity", "triple equals")瑞凑,使用 ===
  • 抽象相等比較 ("loose equality"在塔,"double equals") ,使用 ==
  • 以及 Object.is (ECMAScript 2015 / ES6 新特性)

選擇使用哪個操作取決于你需要什么樣的比較拨黔。

簡而言之,在比較兩件事情時绰沥,雙等號將執(zhí)行類型轉(zhuǎn)換; 三等號將進(jìn)行相同的比較篱蝇,而不進(jìn)行類型轉(zhuǎn)換 (如果類型不同, 只是總會返回 false ); 而Object.is的行為方式與三等號相同,但是對于NaN和-0和+0進(jìn)行特殊處理徽曲,所以最后兩個不相同零截,而Object.is(NaN,NaN)將為 true秃臣。(通常使用雙等號或三等號將NaN與NaN進(jìn)行比較涧衙,結(jié)果為false) 請注意哪工,所有這些之間的區(qū)別都與其處理原語有關(guān); 這三個運(yùn)算符的原語中,沒有一個會比較兩個變量是否結(jié)構(gòu)上概念類似弧哎。對于任意兩個不同的非原始對象雁比,即便他們有相同的結(jié)構(gòu), 以上三個運(yùn)算符都會計(jì)算得到 false 撤嫩。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末偎捎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子序攘,更是在濱河造成了極大的恐慌茴她,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件程奠,死亡現(xiàn)場離奇詭異丈牢,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)瞄沙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門己沛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人帕识,你說我怎么就攤上這事泛粹。” “怎么了肮疗?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵晶姊,是天一觀的道長。 經(jīng)常有香客問我伪货,道長们衙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任碱呼,我火速辦了婚禮蒙挑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘愚臀。我一直安慰自己忆蚀,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布姑裂。 她就那樣靜靜地躺著馋袜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪舶斧。 梳的紋絲不亂的頭發(fā)上欣鳖,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機(jī)與錄音茴厉,去河邊找鬼泽台。 笑死什荣,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的怀酷。 我是一名探鬼主播稻爬,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼胰坟!你這毒婦竟也來了因篇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤笔横,失蹤者是張志新(化名)和其女友劉穎竞滓,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吹缔,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡商佑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了厢塘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茶没。...
    茶點(diǎn)故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖晚碾,靈堂內(nèi)的尸體忽然破棺而出抓半,到底是詐尸還是另有隱情,我是刑警寧澤格嘁,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布笛求,位于F島的核電站,受9級特大地震影響糕簿,放射性物質(zhì)發(fā)生泄漏探入。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一懂诗、第九天 我趴在偏房一處隱蔽的房頂上張望蜂嗽。 院中可真熱鬧,春花似錦殃恒、人聲如沸植旧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽隆嗅。三九已至,卻和暖如春侯繁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背泡躯。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工贮竟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留丽焊,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓咕别,卻偏偏與公主長得像技健,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子惰拱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評論 2 354

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