你真的理解了比較運算符嗎?

平常我們都是不建議在代碼上編寫一些比較難理解的代碼,例如 x == y'A' > 'B' 。這篇文章或許不能給你帶來什麼大的幫助,但是卻可以讓你瞭解一些你可能沒接觸到的知識點。

由於有些參考資料來源於 ECMA 規範,所以感興趣的可能需要先看《讀懂 ECMAScript 規格》這篇文章,當然也可以忽略。

類型之間的轉換表

首先我們需要先了解基本的類型轉換規則。

粗體需要特別留意的,可能跟你想象中的不一樣。

原始值 轉換爲數字 轉換爲字符串 轉換爲布爾值
false 0 "false" false
true 1 "true" true
0 0 "0" false
1 1 "1" true
"0" 0 "0" true
"000" 0 "000" true
"1" 1 "1" true
NaN NaN "NaN" false
Infinity Infinity "Infinity" true
-Infinity -Infinity "-Infinity" true
"" 0 "" false
"20" 20 "20" true
"Runoob" NaN "Runoob" true
[ ] 0 "" true
[20] 20 "20" true
[10,20] NaN "10,20" true
["Runoob"] NaN "Runoob" true
["Runoob","Google"] NaN "Runoob,Google" true
function(){} NaN "function(){}" true
{ } NaN "[object Object]" true
null 0 "null" false
undefined NaN "undefined" false

這裏根據上面的表格列舉些例子:

  • 數字轉字符串

    這個最常用了,這個也很好理解。

    String(123)

    或者

    const a = 123;
    a.toString();
  • 將字符串轉換爲數字

    Number("3.14")    // 返回 3.14
    Number(" ")       // 返回 0
    Number("")        // 返回 0
    Number("99 88")   // 返回 NaN
  • 字符串轉布爾值

    Boolean('test')  // 返回 true
    Boolean('0')  // 返回 false
    Boolean('000')  // 返回 true

== 比較運算符

規則來源於 ECMA 相關規範 Abstract Equality Comparison

== 等同運算符的兩邊的類型不一樣的時候,會有類型自動轉換規則。

相同的類型可以直接比較(相當於 === 比較),無需自動轉換,不同類型有下面幾種自動轉換規則(x == y),規則優先級自上而下:

  1. 如果 x 是 null,y 是 undefined,返回 true

    null == undefined
  2. 如果 x 是 undefined,y 是 null,返回 true

    undefined == null
  3. 如果 x 是 Number,y 是 String,將 y 轉化成 Number,然後再比較

    0 == '0' // true
    0 == '1' // false
  4. 如果 x 是 String,y 是 Number,將 x 轉化成 Number,然後再比較

    '0' == 0 // true
    '1' == 0 // false
  5. 如果 x 是 Boolean,那麼將 x 轉化成 Number,然後再比較

    true == 0 // false
    true == 1 // true
    true == 2 // false
    true == 'test' // false
    false == 0 // true
    false == 1 // false
    false == 2 // false
    false == 'test' // false
  6. 如果 y 是 Boolean,那麼將 y 轉化成 Number,然後再比較

    0 == true // false
    1 == true // true
    2 == true // false
    'test' == true // false
    0 == false // true
    1 == false // false
    2 == false // false
    'test' == false // false
  7. 如果 x 是 String 或者 Number,y 是 Object,那麼將 y 轉化成基本類型,再進行比較

    const a = {}
    1 == a    // false
    '1' == a  // false
    true == a // false
  8. 如果 x 是 Object,y 是 String 或者 Number,將x轉化成基本類型,再進行比較

    const a = {}
    a == 1    // false
    a == '1'  // false
    a == true // false
  9. 其他情況均返回 false

    const a = {}
    a == null
    a == undefined
    0 == null
    '2' == null
    false  === null

即使我們搞懂了 == 的規則,還是建議使用 === 這種嚴格的運算符來替代 ==

> 或者 < 比較運算符

規則來源於 ECMA 相關規範 Abstract Relational Comparison

x < y 的規則步驟如下(規則優先級自上而下):

  1. x 和 y 需要轉換爲原始數據類型(ToPrimitive)

    var px = ToPrimitive(x)
    var py = ToPrimitive(y)
    // 下面會沿用這兩個變量的

    除開原始的數據類型 undefined、null、boolean、number、string、 symbol,其他的都屬於對象,所以可以理解爲這個 ToPrimitive 只對對象有作用。(還有個特殊的 NaN,不需要轉換,NaN 可以理解爲一種特殊的 number,typeof NaN === 'number')。

    如果 x 或者 y 是對象,需要做轉換處理,由於這裏涉及的比較深,這裏還是簡單的說一下,知道有這回事就好。

    var a = {}
    a < 'f' // true
    a < 'F' // false
    // a 會轉變爲 [object Object]
    // 相當於運行了 a.valueOf().toString()

    爲什麼不直接 a.toString() 呢,看下下面的例子你就懂了(會首先運行 valueOf,如果返回的是對象則再運行 toString,否則直接返回 valueOf 的返回值)

    var d = new Date(1572594637602)
    d < 1572594637603 // true
    d < 1572594637601 // false
    // d 會轉變爲 1572594637602 (當前時間轉變的成的毫秒時間戳)
    // 相當於運行了 a.valueOf()

    如果重寫了 valueOf 方法,那麼預期結果就不一樣了

    var d = {}
    // 這裏重寫定義了valueOf
    d.valueOf = () => 1
    d < 2 // true
    d < 0 // false
    // d 會轉變爲 1
    // 相當於運行了 a.valueOf()
  2. 如果 px 和 py 都是字符串

    • 如果 py 是 px 的前綴,返回 false

      'test' < 'te'
    • 如果 px 是 py 的前綴,返回 true

      'test' < 'test1'
    • 如果 px 不是 py 的前綴,而且 py 也不是 px 的前綴

      那麼需要從 px 和 py 的最小索引(假設是 k)對應的字符的 UTF-16 代碼單元值 進行對比。

      假設 m = px.charCodeAt(k),n = py.charCodeAt(k),那麼如果 m < n,返回 true,否則返回 false。

      'A' < 'B' // true
      // 相當於 'A'.charCodeAt(0) < 'B'.charCodeAt(0)

      更加複雜點的例子

      'ABC' < 'ABD' // true
      // 相當於 
      // var a = 'ABC'.charCodeAt(0) < 'ABD'.charCodeAt(0) // false
      // var b = 'ABC'.charCodeAt(1) < 'ABD'.charCodeAt(1) // false
      // var c = 'ABC'.charCodeAt(2) < 'ABD'.charCodeAt(2) // true
      // a || b || c
  3. 其他情況 px 和 py 一律轉爲數字類型進行比較

    var nx = Number(px)
    var ny = Number(py)

    例子

    '2' < 3 // true
    '2' < 1 // false
    var a = {}
    a < 1 // false,相當於,Number(a) < 1
    a < 'a' // true,相當於 '[object Object]' < 'a'
    a < '[' // false,相當於 '[object Object]' < '['
    var b = function(){}
    b < 'g' // true,相當於 'function(){}' < 'g'
    b < 'e' // false,相當於 'function(){}' < 'e'

x > y 的道理一樣,這裏就不多說了。

參考文章

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章