js中 == 的隐式转换规则

163 阅读2分钟

一、数字和其他类型值比较

1、数字和布尔值,将布尔值转为数字

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

2、数字和字符串,将字符串转为数字

      console.log(1 == '1') // true
      console.log(1 == 'a') // false

3、数字和对象,将对象转为字符串再转为数字

      console.log(1 == [1]) // true

二、字符串和其他类型值比较

1、字符串和布尔值,二者转成数字再进行比较

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

2、字符串和对象,将对象转为字符串

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

以上,基本遵循这个规律:

image.png

三、布尔值和其他类型值比较

布尔值和数字比较时,布尔值先转为数字再比较;布尔值和字符串比较时,二者都要转为数字再比较。

所以,现在讨论布尔值和对象比较。它俩进行比较时,将布尔值转为数字,将对象转为字符串再转为数字

      console.log(true == [1]) // true
      console.log(false == []) // true

[1]转为字符串为'1',再转为数字为1,true转数字为1

[]转为字符串为'',再转为数字为0,false转为数字为0

看这个例子:

      console.log(false == ![]) // true

其中,![]是布尔值,![]为false

四、undefined和null比较

      console.log(undefined == null)

五、对象和原始值的比较

当对象隐式转换为原始值时,会经过以下的步骤:

  1. 如果有Symbol.toPrimitive方法,则先调用
  2. 调用valueOf,如果可以转成原来的类型,则返回
  3. 调用toString,如果可以转成原来的类型,则返回
  4. 如果没有返回原始值,则会报错
      const obj = {
        [Symbol.toPrimitive]() {
          return 1
        },
        valueOf() {
          return 2
        },
        toString() {
          return 3
        }
      }

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

在此例中,如果将Symbol.toPrimitive方法注释掉,则obj == 2

六、一道面试题:如何使a == 1 && a == 2 && a == 3返回true

1、a对象中调用任意一个方法都可以做到返回true

      const a = {
        i: 1,
        [Symbol.toPrimitive]() {
          return this.i++
        },
        valueOf() {
          return this.i++
        },
        toString() {
          return this.i++
        }
      }
      console.log(a == 1 && a == 2 && a == 3) // true

2、数组在toString前先调用join方法

      const a = [1, 2, 3]
      a.join = a.shift
      console.log(a == 1 && a == 2 && a == 3) // true

3、数据劫持

      var i = 1
      Object.defineProperty(window, 'a', {
        get() {
          return i++
        }
      })
      console.log(a === 1 && a === 2 && a === 3) // true
      const a = new Proxy(
        { i: 1 },
        {
          get(target) {
            return () => target.i++
          }
        }
      )
      console.log(a == 1 && a == 2 && a == 3) // true