JS 隐式类型转换

看完此文你可以完全不需要背诵复杂冗长的 ECMA 规范, 用逻辑即可推理,现在, 我们假装从 JS 设计者的角度来聊聊隐式类型转换, 首先要记住, JS 作者的”初衷”是美好的, 他希望 == 是最顺手最快捷的比较

[]==false// true 
!![]==true// true 
!!''==false// true
[1]=='1'// true 
''==0// true 
''==false// true
[1]==true// true 
null==0// false
null==''// false

为什么 [] == false ?

首先我们知道 [] 和 false 一个是对象, 一个是布尔值, 类型不同, 需要类型转换再做比较,要注意, JS 中规定, 如果 == 中有布尔值, 只能转换为数字, 那为什么不是转换成字符串呢?
因为如果布尔值转换成字符串那就是 ‘true’ 和 ‘false’, 那这种对比就毫无意义了,这也符合我们的常识, 很多语言也是类似的设定, 也就是 Bool 属于一种 Int
所以此问题可以转换成:

为什么 [] == 0?

我们知道 Primitive(原值)和非 Primitive 比较, 需要把非 Primitive 转换成 Primitive 才可以
[] 是一个对象, 因此需要 toPrimitive()
简单的说, 大部分对象最后都是用 toString() 来转换成 Primitive

继续刨根问底, 为啥每个对象都有 toString 而不是 toNumber 呢?

这就是 JS 对新人友好的地方, JS 的对象都可以打印输出, 自带人性化展示, 在终端上人性化展示, 那当然是用字符串啦, 因此选择用 toString 转换 Primitive 理所因当
我们来看看数组的 toString, 数组的 toString 相当于 join()

[].toString()   // '' 
[1].toString()  // '1'  
[1,2,3,4].toString()  // '1,2,3,4'

所以此问题可以转换成: 为什么 ‘’ == 0 ?

为了验证我们的想法, 我们来尝试一些更奇葩的对象和字符串的 == 比较

[1]=='1'// true  '[object Object]'=={}// true

({}).toString() 是 [object Object], 所以 ‘[object Object]’ == {} 果然也是 true

为什么 ‘’ == 0 ?

字符串和数字比较会把字符串转换成数字(都转成数字能处理的复杂场景更多, 容错性更高!)

'  1  '==1.0// true  '12.10'==12.1// true

这样对开发者就会很方便 要注意, 字符串转成数字不是用的 parseInt() 或者 parseFloat(), 而是 Number()

Number('')  // 0  
Number('abc')// NaN

所以此问题可以继续转换成: 为什么 0 == 0? 显然就是返回 true
推理到此结束, 我们回顾一下这个比较的转换规程

  1. [] == false
  2. [] == 0
  3. ‘’ == 0
  4. 0 == 0
    看到这里我们猛然想明白了为啥 NaN 不能等于自身!

为什么 NaN !== NaN?

我们不妨来看看 ‘abc’ == NaN 做比较的过程
因为 NaN 也是数字类型, 所以我们需要把 ‘abc’ 转换为数字
‘abc’ == NaN 相当于 Number(‘abc’) == NaN 相当于 NaN == NaN, 如果 NaN 可以等于自身的话, 这种情况就会返回 true
那整个隐式转换就乱套了
因此 NaN 不能等于自身也是哑巴吃黄连, 有苦说不出啊

为什么 null == 0 是 false 呢 ?

两边类型不同, 是不是也要类型转换呢?
要是能转的话确实要转, 但 null 和数字0本身已经是 Primitive 了, 没有机会再走一遍 toPrimitive(), 因此等号两边始终无法转换成同类型, 只能返回 false

为什么 null == undefined ?

和上面的问题一样, null 和 undefined 都是 Primitive, 而且也不是字符串或者数字, 转无可转
但 JS 专门规定了 null == undefined 就是返回 true, 属于一种专门的特殊情况

为什么 !![] 是 true?

这里面不涉及任何 == 比较, 和上面的题目完全是两类题目, 千万不可搞混
此题直接判断这个值是不是 Falsy(假值) 即可, 只要不是这几个值, 都是 true
Falsy 的值有 0, ‘’, false, NaN, null, undefined
类似的问题 !![] == true, 因为这个表达式先要计算 !![], 它已经是 true 了

为什么 ESLint 中会各种限制使用 ==?

我觉得完全可以理解, == 虽然也是一种便捷的转换, 但并不符合传统语言的习惯, 工程化企业化的项目不想用这种 “黑魔法” 也是一种正确的选择。

你可能感兴趣的:(JS 隐式类型转换)