JavaScript == 和 ===


imundefined, 微信公眾號前端 Q 原創, 申訴證明

== 操作符(Equality,相等操作符)

相等操作符會做類型轉換。

我們先來看看什么是類型轉換(type coercion)

當操作符兩邊的操作數是不同類型時,其中一個操作數將轉換為另一個操作數同類型的“等效”值。比如:

12 - '3' // 9, 將 string 類型轉換成 number 類型,相當於 12 - Number('3')
12 - 'hello' // NaN, 因為 Number('hello') 為 NaN,12 - NaN 為 NaN
'3' - 12 // -9, 同樣轉成 number 類型
12 - true // 11, Number(true) 為 1
false - 12 // -12, Number(false) 為 0
12 + '3' // 123, 將 12 轉換成 string 類型,再連接 '3'

看上去很簡單對不對?減法將非 number 類型的轉換成 number 類型的,加法將 number 類型轉換成 string 類型的,真的這樣嗎?看下面:

12 + true // 13,這里將布爾類型 true 轉換成數值類型 1,相當於 12 + Number(true)

從上面可以看出,“加法將 number 類型 轉換成 string 類型”這個總結並不正確,事實上,類型轉換並不單單看操作符,也就是並不只是看你做加法還是做減法,還要看你的類型,我們從上面的規律中做下總結:

  • number - string 將 string 轉換成 number
  • string - number 將 string 轉換成 number
  • number - boolean 將 boolean 轉成 number
  • boolean - number 將 boolean 轉成 number
  • number + string 將 number 轉成 string
  • number + boolean 將 boolean 轉成 number
  • ...

有點眼花,也不是很有規律。有時候類型轉換還可能會調用 toString 方法,加上操作符有很多,像 +、-、*、/、%、= 等等,再加上 5 種基本數據類型 Number、String、Undefined、Null、Boolean,還有引用類型 Object,這樣組合起來,類型轉換的規律就很難掌握了。

比如下面這個:

[1] - 3 // -2, 相當於 Number([1].toString()) - 3
[1, 2, 3] - 3 // NaN, 這里 toString 之后 會得到 '1,2,3',轉成 number 就是 NaN
[[]] - 3 // -3, [[]].toString 是 "","" 轉成 number 類型是 0
5 * '1' // 5, Number('1') 為 1
5 * 'true' // NaN, Number('true') 為 NaN
5 * true // 5, Number(true) 為 1

是不是覺得規則已經比較難記憶了?

回到我們的 == 操作符

相等操作符在比較時,如果左右兩邊的類型不同,也會將左邊或者右邊的操作數轉換成與對方同類型的等效值。比如:

12 == "12" // true, string 類型轉換成 number 類型
1 == true // true, boolean 類型轉換成 number 類型
true == '1' // true, 兩者都轉換成 number 再比較? 還是 '1' 轉換成 boolean 類型?
true == '2' // false?? Boolean('2') 可是等於 true 哦,結合上面一條語句,可以得出應該是兩者都轉換成 number 再比較

再來看看 == 操作符的傳遞性

0 == '' // true
0 == '0' // true
'' == '0' // false

可以看出,== 操作符不滿足傳遞性

再來看幾個例子:

false == 'false'    // false
false == '0'        // true

false == undefined  // false
false == null       // false
null == undefined   // true

' \t\r\n ' == 0     // true

是不是覺得還能理解,但可能記不住了?所以,如果你不了解所有的規則,最好不要使用相等操作符,而是使用恆等操作符,下面這張圖比較有說服力,來自 dorey.github.io,綠色表示相等操作符運算后結果為 true:
相等操作符

規則這么多,掌握不好容易出錯。

=== 操作符(Identity,恆等操作符)

很多人認為恆等操作符代表值相等,並且有相同的類型,但這是不對的,來看下面的例子:

var a = [1, 2, 3],
    b = [1, 2, 3],
    c = {},
    d = {};
console.log(a === b); // false
console.log(c === d); // false

可見,即使是相同的類型,而且值相等,也不一定恆等。

恆等

恆等操作符有三種情況:

  1. 兩個操作數都是引用類型,他們都引用同一個 object,即地址相同,則恆等成立。
  2. 兩個操作數都是基本數據類型 (Boolean、Number、String、Undefined、Null),如果值相同,則恆等成立。
  3. 一個操作數是引用類型,另一個是基本數據類型,恆等不成立。

上面的例子不等是因為地址不同。我們再來看看比較特殊的 String:

String 的基本數據類型和基本包裝類型

我們知道,基本數據類型不是引用類型,應該是沒有方法的,比如 'hello world',但你確實可以用 'hello world'.split("") 分割字符串,這是因為調用 split 這個方法的時候,后台就會創建一個基本包裝類型的對象 (new String('hello world')),我們實質上是從這個基本包裝類型里獲取的方法,這樣的基本包裝類型還有 Boolean 和 Number。

要明確,'hello world' 只是一個基本數據類型,不管它是拼接而成還是直接以字面量的形式形成,比如:

var a = 'hello' + ' world',
    b = 'hello world';
console.log(a === b); // true

因為 a、b都是基本數據類型,所以直接比較值,是相等的,那么恆等成立。

但如果是這樣:

var a = 'hello world',
    b = new String('hello world');
console.log(a === b); // false, 因為 a 是基本數據類型,b 是引用類型,恆等不成立。

來看一下恆等操作符的比較情況:
恆等操作符

所以 Douglas Crockford 建議我們永遠不使用 == 操作符,而是使用 === 操作符

另外,在引用類型的比較上 == 和 === 的表現還是一致的,因為不論是否有類型轉換,值都是地址,即比較的都是地址,地址相同則相同,如有不對,還望指出:

var a = [1, 2, 3],
    b = [1, 2, 3],
    c = {},
    d = {},
    e = a;
console.log(a === b); // false
console.log(c === d); // false
console.log(a == b); // false
console.log(c == d); // false
console.log(a == e); // true
console.log(a === e); // true
console.log([0] == (new String("0"))); // false
console.log([0] === (new String("0"))); // false

參考
Which equals operator (== vs ===) should be used in JavaScript comparisons?
JavaScript-Equality-Table
《JavaScript 高級程序設計》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM