分析 JS 隐式类型转换的问题

一般隐式转换会存在两个场景中:

  1. 数学运算符
  2. 逻辑语句中

数学运算符

数学运算符又分:加、减、乘、除

减、乘、除

我们在对各种非Number类型运用数学运算符(- * /)时,会先将非Number类型转换为Number类型。
例如:

1 - true // 0, 首先把 true 转换为数字 1, 然后执行 1 - 1
1 - null // 1,  首先把 null 转换为数字 0, 然后执行 1 - 0
1 * undefined //  NaN, undefined 转换为数字是 NaN
2 * ['5'] //  10, ['5']首先会变成 '5', 然后再变成数字 5

其中最后一个例子是这样的,遇到引用类型先调用valueOf() 然后再调用 toString() 进行转换

加法比较特殊

优先级从上向下:

  1. 一侧为 String 类型时,另一侧会尽量转化成为字符串类型
  2. 一侧为 Number 类型时,且另一侧为基本数据类型,则另一侧会尽量转换成 Number 类型
  3. 一侧为 Number 类型,且另一侧为引用类型,会将它们俩都转换成 String 类型然后拼接
  4. 两侧都是基本类型,且都不是 String,Number。则两侧都会尽量向 Number 类型去转换
  5. 两侧都是引用类型,都转换成 String 类型然后拼接

例如:

/**规则一**/
"233" + 1 // "2331" 
"233" + [] // "233"

/**规则二**/
123 + true // 124
123 + false // 123
123 + null // 123
123 + undefined // NaN

/**规则三**/
123 + [] // "123"
123 + [123] // "123123"
123 + {a: 1} //  "123[object Object]"

/**规则四**/
true + null // 1
undefined + null // NaN
// 也可以得知:true => 1, false => 0 , null => 0 , undefined => NaN

/**规则五**/
[] + [] // ""
[123] + {a: 1} //"123[object Object]"
[] + function(a){console.log(a)} //"function(a){console.log(a)}"

逻辑语句中的类型转换

通常都是 if(xxx),或者while(xxx == xx) 还有for循环中也会判断逻辑,还有 ||,&&

单个变量 (也就是没有 == 的时候)

如果只有单个变量,会先将变量转换为Boolean值。(其实逻辑运算符也是单个单个地判断变量的)

0 && false // 0 因为 左边 0 优先转换为 false,然后因为是 && 所以就不看后面的了
"0" && false // false 因为 左边 "0" 优先转换为 true,然后因为是 && 继续去看后面,看见 false ,然后表达式的值就算 false了。
0 || false // false 因为 左边 0 优先转换为 false,因为是 || ,得继续看后面,所以表达式的结果是 false
"0" || false // "0" 因为 左边 "0" 优先转换为 true, 然后因为是 || 所以就不看后面的了

其中涉及的 || ,&& 逻辑运算符就不在这里赘述了。

使用 == 比较 (所以还是务必使用 === )
  1. NaN和其他任何类型比较永远返回 false(包括和他自己)。
  2. Boolean 和其他任何类型比较,Boolean 首先被转换为 Number 类型。
  3. String和Number比较,先将String转换为Number类型。
  4. null == undefined比较结果是true,除此之外,null、undefined和其他任何结果的比较值都为false。
  5. 原始类型和引用类型做比较时,引用类型会依照ToPrimitive规则转换为原始类型。
    说人话就是:调用先valueOf然后调用toString
    如果还是没法得到一个原始类型,就会抛出 TypeError。
/**规则一**/
NaN == NaN // false

/**规则二**/
true == 1  // true 
true == '2'  // false, 先把 true 变成 1,而不是把 '2' 变成 true
true == ['1']  // true, 先把 true 变成 1, ['1']拆箱成 '1', 再参考规则3
true == ['2']  // false, 同上
undefined == false // false ,首先 false 变成 0,然后参考规则4
null == false // false,同上

/**规则三**/
123 == '123' // true, '123' 会先变成 123
'' == 0 // true, ''" 会首先变成 0

/**规则四**/
null == 0 //false, 虽然null有些时候会隐式转换成 0. 但这里是不相等的!
null == undefined //true
undefined == false // false
undefined == false // false

/**规则五**/
'[object Object]' == {a: 1}  // true, 对象和字符串比较,对象通过 toString 得到一个基本类型值
'1,3' == [1, 3]  // true ,同上

Tips

还有一种东西叫做 Object.is()

Object.is(value1, value2) 方法判断两个值是否为同一个值

简单概括一下它,

  • 基本数据类型:就单纯的肉眼看长得一不一样,长得一样就是相等的,例如:
Object.is(NaN, NaN) // true
Object.is(+0, -0) // false
  • 引用类型:地址一样就一样
Object.is({}, {}) //false

let a = {};
let b = a;
Object.is(a, b) //true

淦!为什么不用TS啊!!

参考

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