一起来了解JS的隐式转换吧

576 阅读3分钟

这是我参与更文挑战的第18天,活动详情查看: 更文挑战

前言

大家都知道,js是一个弱类型语言,所以它的隐式转换太神奇了,跟孙悟空的72变一样,变化多端,不管你是工作几年的老油条,还是初入职场的萌新,稍有不慎,可能你就踩坑了。这篇文章尝试把这个梳理一遍,争取能讲清楚,如果有问题,欢迎指正。

数据类型

我们先来了解js的数据类型有哪些?

基本类型: Number, Boolean, String,Null, Undefined, Symbol(新引入,这里暂不做讨论), BigInt(新引入,这里暂不做讨论)
引用类型: Object(Function,ArrayDate等都属于Object)

隐式转换

转换规则

转换规则主要有这么几类

  • 转原始值(ToPrimitive)
  • 转字符串(ToString)
  • 转数字 (ToNumber)
  • 转布尔值 (ToBoolean)

下面一个个来讲

转原始值(ToPrimitive)

对象类型转原始值会遵循一下规则:

  1. 先调用对象的valueOf方法,如果valueOf返回的是原始值,则返回该值;
  2. 如果不是原始值,则再调用toString方法,如果返回的是原始值,则返回该值;
  3. 如果不是,则报错。

补充:
valueOf方法和toString方法没有被改写的情况下
数组会返回字符串,逗号分隔,空数组会返回'',如果元素是null或者undefined,则会把该元素当作空字符串''
函数会返回该函数的字符串形式
对象会返回'[object Object]'

例子:

var obj = {
   valueOf () {return '答案'},
   toString () {return 'cp3' }
}
console.log(obj == '答案') // true

var obj = {
   valueOf () {return {}},
   toString () {return '答案cp3'}
}
console.log(obj == '答案cp3') // true


console.log([1,2,3] == '1,2,3') // true
console.log([] == '') // true
console.log(function a () {} == 'function a () {}') // true
console.log({} == '[object Object]') // true
转字符串(ToString)

别的类型转字符串的规则如下:

  • Boolean类型: truefalse转成 'true''false'
  • Number类型: 01转成 '0''1'
  • Object类型: 遵循上面的对象转原始值流程;
  • Null类型: null 转成 'null'
  • Undefined类型: undefined 转成 'undefined'

例子如下:

console.log(String(false)) // 'false'
console.log(String(123)) // '123'
console.log(String({})) // '[object Object]'
console.log(String(null)) // 'null'
console.log(String(undefined)) // 'undefined'
转数字 (ToNumber)
  • Boolean类型: truefalse转成 10
  • String类型:数字字符串转成数字,空字符串转成0, 其它字符串则是NaN
  • Object类型: 遵循上面的对象转原始值流程;
  • Null类型: null 转成 0
  • Undefined类型: undefined 转成 NaN

例子如下:

console.log(Number(false)) // 0
console.log(Number('123')) // 123
console.log(Number({})) // NaN 对象会先按照上面转原始值流程,转成字符串后再用字符串的方法,最后得到NaN
console.log(Number([1])) // 1
console.log(Number(null)) // 0
console.log(Number(undefined)) // NaN
转布尔值 (ToBoolean)
  • ''
  • 0
  • false
  • null
  • undefined
  • NaN 这六个都是转布尔值是转成false,其它都是转成true

例子如下:

console.log(Boolean('')) // false
console.log(Boolean(0)) // false
console.log(Boolean(false)) // false
console.log(Boolean(null)) // false
console.log(Boolean(undefined)) // false
console.log(Boolean(NaN)) // false
console.log(Boolean('123')) // true
console.log(Boolean({})) // true
console.log(Boolean([1])) // true

规则主要是这些,下面来看看发生隐式转换的主要场景。

主要场景

发生隐式转换主要有==相等,, 算术运算符(+-*, /等), 比较运算符(>,<),if判断,while循环, 取非等场景,不同场景转换的类型不一样,运用的规则也不一样。

==相等

=====不同,==不会判断类型,只会根据转换后的值去判断,如果相等,就相等。
有以下转换规则:

  1. String类型和Number类型比较,String类型会转成Number类型(参考上面的String类型转Number规则),然后再比较。
    console.log('123' == 123) // true
    console.log('' == 0) // true
    
  2. Boolean类型和其它类型比较,Boolean类型会转成Number类型(参考上面的Boolean类型转Number规则),然后再比较。
    console.log(1 == true) //  true 
    console.log(123 == true) // false
    console.log(0 == false) // true
    console.log('0' == false) // true
    
  3. Object类型与其它类型比较
    • 如果是基本类型,则会转原始值(参考上面转原始值的规则)
    • 如果是Object类型,则会比较是不是同一个对象(栈地址相同),如果是同一个对象,则是true
      console.log({} == '[object Object]') // true
      console.log({} == {}) // false 因为栈地址不一样
      var a = b = {}
      console.log(a == b) // true
    
  4. Null类型与 Undefined类型相等,与其它类型都不相等。NaN与任何值都不相等。
    var a = null
    var b = undefined
    console.log(a == b) // true
    var a = b =  NaN
    console.log(a == b) // false
    
算术运算符
  • 减,乘,除(-*, /)会把类型转Number类型(依照上面转Number类型规则)。
    console.log('10' / 2) // 5
    var a = {
     valueOf () {return 10}
    }
    console.log(a * 10) // 100
    console.log(true - 1) // 0
    
  • 加号(+) 要分情况
    • 类型如果是String类型,则会认为是拼接,而不是相加+

    • 类型如果是Object类型,如果拿到的原始值是String类型,则也是拼接。

    • 其它类型,会转成Number类型,再相加+

    • NaN与任何相加都会等于NaN

      console.log('1' + '2') // ‘12’ 拼接
      var a = {valueOf () { return'2'}}
      console.log(1 + a) // '12'
      console.log(true + 2)  // 3
      console.log(undefined + 1) // NaN  因为undefined转成NaN
      console.log(null + 1) // 1 因为null转成0
      
比较运算符(>,<, >=, <=等)

其它类型跟数字比较,会把其它类型转成Number类型(参考各个类型转Number类型规则),然后再比较。

如果都是字符串类型,则不会转成Number类型,而是用字符串的第一个字符的ASCII码比较

NaN与任何类型比较都会返回false

var a = {valueOf () { return 2}}
console.log(a > 1) // true
console.log('2' > 1) // true
console.log('a' > 1) // false
console.log(NaN > 1) // false
console.log('12' > '2') // false
if判断,while循环

会把类型转成Boolean类型(参考各个类型转Boolean类型规则),再判断。

if(123) // true
if(0) // false
while('答案cp3') // true
while(null) // false
取非(!)

会把类型转成Boolean类型(参考各个类型转Boolean类型规则), 然后再取反

console.log(!'') // true
console.log(!123) // false
console.log(![]) // false  因为先把[]转Boolean类型为true, 取反true为false,下同
console.log(!{}) // false

总结

讲了这么多,希望对你们理解js的隐式转换有一点点的帮助~