【面试宝典】隐式转换

518 阅读4分钟

隐式转换规则

1.ToString、ToNumber、ToBoolean、ToPrimitive

首先了解一下 js 数据类型之间转换的基本规则,比如数字字符串布尔型对象数组之间如何进行转换。

1.1 ToString

注意区别toString方法,ToString是指其他类型转换为字符转类型的操作。 这里我们讨论 nullundefined布尔型普通对象数组转换为字符串的规则

  • null:转换为'null'
  • undefined:转换为'undefined'
  • 布尔类型:truefalse分别转换为'true''false'
  • 数字类型:转换成数字的字符串形式,11转换为'11'1e21转换为'1e+21'
  • 普通对象:转换字符串相当于直接调用Object.prototype.toString(),返回'[object Object]'
  • 数组类型:相当于调用Array.prototype.join()方法,['1','2','3']转换成'1,2,3'[]转换为空字符串,数组中的nullundefined会被当做空字符串处理
String(null) // 'null'
String(undefined) // 'undefined'
String(11) // '11'
String(1e21) // '1e+21'
String({}) // '[object Object]'
String([]) // ''
String(['', null, undefined]) // ',,'

注意:上面所说的规则是在默认的情况下,修改默认的toString(),会影响结果

1.2 ToNumber

ToNumber是指其他类型转换为数字类型的操作

  • null:转换为0
  • undefined:转换为NaN
  • 布尔类型:true转换为1false转换为0
  • 字符串类型:如果是纯数字形式,则转换为对应的数字,空字符串转换为0,其他一律按转换失败处理,为NaN
  • 对象类型:数组会先被转换为原始类型,也就是ToPrimitive,然后再把转换后的原型类型按照上面的规则处理,ToPrimitive会在下文介绍
Number(null) // 0
Number(undefined) // NaN
Number('123') // 123
Number('') // 0
Number('123e') // NaN
Number([]) // 0
Number(['1', '2']) // NaN
Number({}) // NaN

1.3 ToBoolean

ToBoolean是指其他类型转换为布尔类型的操作
js中的假值只有nullundefined0''NaN,其余都为真值

Boolean(null) // false
Boolean(undefined) // false
Boolean(0) // false
Boolean('') // false
Boolean(NaN) // false
Boolean([]) // true
Boolean({}) // true

1.4 ToPrimitive

ToPrimitive是指对象类型(普通对象、数组)转换为原始类型的操作

  • 当对象类型需要转换为原始类型时,会先查找对象的valueOf方法,如果valueOf返回的是原始类型的值,那么ToPrimitive就返回这个结果。
  • 如果valueOf返回的不是原始类型,或者valueOf方法不存在,就调用对象的toString方法,也就是遵循对象的ToString规则,然后使用toString的返回值作为ToPrimitive的返回值。
  • 如果valueOftoString都没有返回原始类型的值,则抛出异常。
Number([]) // 0
Number(['1']) // 1
const obj2 = {
    valueOf(){
        return '11';
    },
    toString(){
        return '12';
    }
}
Number(obj2) // 11
const obj3 = {
    toString(){
        return '123';
    }
}
Number(obj3) // 123
const obj4 = {
    toString(){
        return {};
    }
}
Number(obj4) // Uncaught TypeError: Cannot convert object to primitive value

2.宽松相等(==)比较时的隐式转换规则

宽松相等(==)严格相等(===)的区别在于宽松相等会在比较中进行隐式转换。现在我们来看看不同情况下的转换规则。

2.1 布尔类型和其他类型比较

  • 只要布尔类型参与比较,该布尔类型的值会先被转换为数字类型
  • 根据布尔类型ToNumber规则,true转换为1false转换为0
false == 0 // true
true == 1 // true
true == 2 // false

2.2 数字类型和字符转类型比较

  • 数字类型字符串类型进行比较时,字符串类型会被转换成数字类型
  • 根据字符串的ToNumber规则,如果是纯数字形式的字符串,则转为对应的数字,空字符转为0, 否则一律按转换失败处理,转为NaN
  0 == '' // true
  1 == '1' // true
  1e21 == '1e21' // true
  Infinity == 'Infinity' // true
  true == '1' // true
  false == '0' // true
  false == '' // true

2.3 对象类型和原始类型比较

  • 对象类型原始类型做相等比较时,对象类型会依照ToPrimitive规则转换为原始类型
  '[object Object]' == {} // true
  '1,2,3' == [1, 2, 3] // true
  [2] == 2 // true
  [null] == 0 // true
  [undefined] == 0 // true
  [] == 0 // true

2.4 null、undefined和其他类型比较

  • nullundefined宽松相等的结果为true,其他都为false
  null == undefined // true
  null == false // false
  undefined == false // false

3.经典面试题

定义一个变量a,使得下面的表达式结果为true

  a == 1 && a == 2 && a == 3

对象每次和原始类型做==比较时,都会进行一次ToPrimitive操作,那我们是不是可以定义一个包含valueOftoString方法的对象,然后通过某个值的累加来实现?

const a = {
    value: 1,
    valueOf(){
        return this.value++;
    }
}
a == 1 && a == 2 && a == 3 // true