面试题:

js中运行 '10'+3-3 = ?

A. 10

B.  0

C. 100

D. undefined

正确答案 C 

为什么结果不是 10 ,下面一起来了解JS的隐式转换吧

js是弱类型语言,具体有下面这些类型

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

转换规则主要有这么几类

  • 转原始值
  • 转字符串
  • 转数字 
  • 转布尔值 
转原始值

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

  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
转字符串

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

  • 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'
转数字
  • 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
转布尔值
  • ''
  • 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类型规则),然后再比较。

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
复制代码
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