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)行的比較如下圖所示:
在上面的表格中,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.NaN 與 NaN 視為不相等宵膨。
示例
// 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 撤嫩。