JavaScript 中一些不经意的隐式类型转换

前言

这在以前很常见,比如 if 条件中的 ==,使用 + 接接字符串,如果不明白这些隐式转换,很容易掉坑,久久不能自拔。

算术运算符|字符串连接符

前面7个中的 + 号为算术运算符,剩余的为字符串连接符

console.log(
  undefined+undefined,   // NaN
  undefined+1,           // NaN
  null+null,             // 0
  null+1,                // 1
  1-false,               // 1
  1-true,                // 0
  1-'true',              // NaN
  NaN+NaN,               // NaN
  ''+NaN,                // "NaN"
  ''+undefined,          // "undefined"
  ''+null,               // "null"
  ''+[],                 // ""
  ''+{},                 // "[object Object]"
  []+[],                 // ""
  []-[],                 // 0
  []+{},                 // "[object Object]"
  {}+{},                 // "[object Object][object Object]"
  1+[]                   // "1"
)

一、 加号

对于 undefined 和 null ,如果 + 为算术运算符则 undefined 和 null 会通过 Number() 方法尝试转成数字类型,

Number(undefined) 值 为 NaN,Number(null) 值 为 0

1.+ 号两边只要有一边为字符串,则此时 + 号为字符串连接符,并调用 toString() 方法把其它类型转为字符串类型,

2.+ 号两边都不为字符串,此时 + 号有可能是算术运算符或者字符串连接符。

对于对像的话就会先转成字符串(调用 toString() 方法)

二、非加号

除了 + 号以久,其它的运算符(-、/、*)都不会有这种歧义,只有一种就是算术运算符,所以符号两边都会转成数字类型再进行运算。

基本上面的结论,我们就可以实现快速的类型转换(转数字)

console.log(
  '123'-0, // 减
  '123'*1, // 乘
  '123'/1, // 除
)

上面都会隐式地把字符串类型的 '123' 转成 数字类型的 123。

关系运算符

console.log(
  'abc' == 1,                // false,注:'abc' 转换成 NaN
  '1' == 1,                  // true
  '1' == true,               // true, 注:'1' 转换成 1,true 转为成 1
  '1' == {name:'1'},         // false,注:{name:'1'} 转成 "[object Object]"
  'a' == ['a'],              // true, 注:['a'] 转成 'a'
  'a,b,c' == ['a','b','c'],  // true, 注:['a','b','c'] 转成 'a,b,c'
  1 == true,                 // true
  1 == {},                   // false,注:{} 被 toString() 转成 "[object Object]",再被 Number() 转成数字结果为 NaN
  {} == '{}',                // false
  {} == true,                // false
  {} == [],                  // false,注:对象与对象地址的比较
  {} == {},                  // false
  [] == [],                  // false
  undefined == null,         // true
  null == null,              // true
  null == [],                // false
  null == '',                // false
  null == 'null',            // false
  null == false,             // false
  null == 1                  // false
)

undefined 和 null 除了与自身及彼此相等外与任务值都不等。

字符与数字比较,字符串转数字

字符串与对象比较,对象转字符串

对象与布尔值,比较时,对象会先转成字符串再转成数字,而布尔值会转换成数字。

对象与字符串比较,对象直接转字符再进行比较。

上面的字符串与数组比较时,数组调用了数组的 toString() 方法把数组转成字符串。

上面有一个需要注意的就是 null+null 值为 0,因为 Number(null) 为 0。

console.log(
  'a' > 'b',       // false
  'aaaa' > 'aac',  // false
  'ab' > '18',     // false
  '81' > '18',     // true
  'abc' > 'acb'    // false
)

不管比较符号两边是何种类型的字符串,也不管两边的字符串长度是多少,在比较时都会对位(对应位置)比较,即字符串的第一位与字符串的第一位比较,直到分出大小全部对比完为止(以长度最短的字符串为准)

字符串进行比较时会调用 charCodeAt() 方法转成 ASCII 值后再进行比较。

注意:如果只是单纯显式地对字符串高用 charCodeAt() 方法,返回的结果是字符串第一个字符的 ASCII 值。