JS 数据类型转换规则(三)

avatar
前端工程师 @豌豆公主

JS 数据类型转换规则(三)- loose equals vs strict equals

引言

  • 没错,这一篇要讲的是 宽松相等(loose equals) 和 严格相等(strict equals)
  • 我们平时记得是== 检查值是否相等 ; === 检查值和类型是否相等,其实不然。正确的解释是:”==“容许在相等比较中进行强制类型转换(比较的是转换后的值) ,而===不容许类型转换。如果类型不一样,则直接返回false
  • == 会进行类型转换,这也是今天要把它写入类型转换的原因

字符串和数字之间的比较

  • 类型不一致时,字符串与数字做宽松比较,字符串会做 Number()的隐式转换
let a = '11';
let b = 11
console.log(a == b) // true

+++
Number('11') // 11
11 == 11

其他类型和布尔值的比较

  • 类型不一致时,布尔值,则会进行Number()的隐式转换
let a = '11';
let b = true;
let c = false
console.log(a == b) // false
console.log(a == c) // false
+++
Number(true) // 1
Number(false) // 0

null和undefined之间的比较

  • null 只和 undefined 相等
null == undefined // true

对象和非对象之间的比较

  • 类型不一致时,对象会经过 Symbol.toPrimitive -> valueOf()-> toString()。转换之后,和非对象进行比较
let a = 42;
let b = [42];
console.log(a == b)
+++
1. [42][Symbol.toPrimitive] // undefined
2. [42].valueOf() // [42]
3. [42].toString() // '42'
4. Number('42') // 42

所以 a == b

对象 和对象比较

  • 比较的是堆内存地址,地址相同则相等

比较少见的情况

  • 通过对象和非对象之间的任一比较环节,去改变返回值。会影响整个结果
Number.prototype.toString = () =>{
    return 3
}
new Number(2) == 3 // true


所以下面这道题就会变得很简单
```js
if (a == 2 && a == 3 && a == 4) {
     // ...
}

只需要在对象和非对象之间比较的任一环节,改变返回值即可。

let arr  = [2,3,4]
arr.toString = arr.shift
if (arr == 2 && arr == 3 && arr == 4) {
    console.log('both ok')
}

如果类型一致,则不会继续做类型转换

 [] == true // flase
 ![] == true // false

+++
true=> Number(true) // 1
[] =>  Number([]) // 0
所以 [] == truefalse
+++
![] => Boolean(![]) // false
fase == true // 此时类型一致,不再进行比较,结果 是flase

练习

  1. 0 == {} // false

image.png 2. 0 == null // false

这是一个特殊的,因为 null 只和undefined 相等,不做类型转换

  1. '' == [] // true

image.png 转换为''之后,因为类型已经相等,所以不再进行类型转换

  1. false == [] // true

image.png

总结

  • ===== 选择哪一个取决于是否容许在相等比较中发生强制类型转换。比如无法判断后端返回的是数字还是字符串,判断 null 和undefined时,建议使用==。除此之外,还是使用全等吧,毕竟安全
  • 个人建议,无论在什么情况下,都不要使用 == true 和 == false。 因为如果类型不同,会转Number。

最后

  • 看过很多库的实现,对类型的把控是很严格的,都会显示的进行强制类型转换,防止隐式带来不必要的麻烦
  • 到这里,数据类型转换就要告一段落了,如有疑问可以看往期文章。