相等與隱含轉型

相等與隱含轉型

嚴格相等

嚴格相等會判斷等號兩邊的 型別 皆相同
以下為特例,NaN 為非數值,所以不管是嚴格或是寬鬆相等都會回傳 false

1
2
console.log(NaN === NaN)    // false
console.log(+0 === -0) // true

而 0 代表 false,!0 會轉為 true,因此會變成 Number(1) == Number(!0)
1 == 1,所以結果會是 true

1
console.log('1' == !0)      // true

寬鬆相等

布林、字串在寬鬆相等時會自動轉型為 數值,這個行為又稱為 隱含轉型

1
2
console.log(17 == '0x11')   // true
// 16進位制 0x1 = 16, 0x11 = 16 + 1

當 true 字串轉型為數值時,會變成 NaN,因此兩者不相等

1
2
console.log(true == 'true') // false
console.log(Number('true')) // NaN

Null、undefined

Null 和 undefined 在比對上不會被轉為數字型別來做比對
但是在寬鬆相等下,Null 和 undefined 會相等

1
2
3
4
5
console.log(Number(null))        // 0
console.log(Number(undefined)) // NaN
console.log(null == 0) // false
console.log(null == undefined) // true
console.log(null === undefined) // false

物件與非物件

物件與非物件的比對,會依照 左邊的型別,對右邊使用包裹物件進行轉換
以下範例來說,左邊是一個字串 10,因此會用 String 包裹物件將兩邊進行轉換

1
2
3
console.log('10' == [10]) // true
console.log(String('10') == String([10]))
// '10' == '10'

純物件會使用 String 包裹物件進行轉換,但通常物件不會這樣進行比對

1
2
console.log(String({A: 'A'})) // '[object Object]'
console.log('[object Object]' == {A: 'A'}) // true

物件與物件

物件與物件的比對是使用傳參考的方式進行比對,因為參考位置不同,所以結果也就不相同,相關觀念可參考 物件傳參考

1
2
console.log({} == {}) // false
console.log([] == []) // false

Truthy 與 Falsy

Truthy(真值)指的是布林值轉換後為真的值,反之則為 Falsy(假值)

需要特別注意的是 假值 的部分:

  • undefined、null 屬於 Falsy
  • "" 屬於假值,但 " " 屬於真值
  • NaN 屬於假值,和任何東西比對(包含自己)都是 false
  • 假值本身如果套用包裹物件後會轉為物件,並為真值
1
2
3
4
5
6
if(new Object(undefined)) {
console.log('true')
} else {
console.log('false')
}
// true

關於真值假值的判斷可以參考 JS Comparison Table


邏輯運算子

邏輯運算子常被運用在布林值的轉換,當第一個數值轉換為 true

  • &&:回傳 第 2 個值,否則回傳 第 1 個值
  • ||:回傳 第 1 個值,否則回傳 第 2 個值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var a = '123';		// true
var b = 456; // true
var c = NaN; //false
var d = undefined; // false
var e = ""; // false

console.log( a && b ) // true(2) => 456
console.log( a || b ) // true(1) => '123'
console.log( c && d ) // false(1) => NaN
console.log( c || d ) // false(2) => undefined

console.log( e && a ) // false(1) => ""
console.log( e || a ) // false(2) => '123'
console.log( e && b ) // false(1) => ""
console.log( e || b ) // false(2) => 456

例(1)

而因為 && 優先序高於 ||,所以會先比對完 && 後,再由左至右比對,因此下列範例的流程會是

  1. c && c => 0
  2. c || 0 => 0
  3. 0 || a => 1
1
2
3
4
var a = 1;
var b = 2;
var c = 0;
console.log( c || c && c || a ) // 1

例(2)

  1. a && b => b
  2. c && a => c
  3. b || c => b
1
2
3
4
var a = 1;
var b = 2;
var c = 0;
console.log( a && b || c && a ) // 2

例(3)

  1. 1000 < 10000 => true
  2. true 轉型後是 1
  3. 1 < 10 => true
1
console.log(1000 < 10000 < 10) // true

參考資料