一、前言

在项目开发或者面试中经常出现下面这种判断:

1
2
3
4
5
console.log({} - {});
console.log([] - []);
console.log([] + [1, 2]);
console.log([] == ![]);
console.log({} == {});

结果分别是:NaN、0、1,2、true、false

二、包装类

包装类是我们理解隐式转化的基础工具,是理解隐式转化的根基。
js 中包装类分为:Boolean()、Number()、String()。

Boolean()

Boolean()只有两种值:truefalse
其中值为false的称为falsey虚值,分别包括 0、null、undefined、false、’’,NaN;
而值为true的称为truth,除了falsey其他的返回都是true

Number()

Number()的处理就分为对 基础类型 的处理和 引用类型 的处理。

基础类型

1
2
3
4
5
6
7
8
console.log(Number(null)) // 0
console.log(Number(undefined)) // MaM
console.log(Number('1')) // 1
console.log(Number('')) // 0
console.log(Number(NaN)) // NaN
console.log(Number('1ab') // NaN
console.log(Number(false)) // 0
console.log(Number(true)) // 1

其中为NaN的数值分别有undefinednull'1ab'
null表示”没有对象”,即该处不应该有值。 undefined表示”缺少值”,就是此处应该有一个值,但是还没有定义。
'1ab'NaN是因为字符串转换中出现了非数字的就会转换成NaN

引用类型

假如我们现在有下面这么一个对象:

1
2
3
4
5
6
7
8
const obj = {
toString() {
return 2;
},
valueOf() {
return 1;
},
};

如果用Number()去取值的时候就会调用到valueOf()方法,此时会返回 1 ,但如果改写 valueOf() { return {} } 的话就会去调用 toString(), 此时返回 2
所以Number(引用类型)的逻辑过程就是:

String()

String()就是跟Number()相反,先调用toString()然后再看valueOf()

1
2
3
4
5
6
7
8
9
10
const obj = {
toString() {
return {};
},
valueOf() {
return 1;
},
};
console.log(String(obj)); // 1
console.log(String({})); // [object Object]

3 < 2 < 1 和 2 < 1 < 1
两个输出都是true,第一个符合数学公式,第二个就涉及到隐式转换了

  1. 比较 2 < 1 结果为 fasle
  2. 现在就是 false < 1 ,Number(false) 为 0
  3. 现在就是 0 < 1, 结果为 true

三、隐式转换规则

boolean 隐式转换触发

  1. if
  2. switch
  3. while
  4. for(;;)
  5. &&
  6. ||
  7. !
  8. !!
  9. ? : 三元运算

number 隐式转换触发

用到数字运算符的地方都会进行转换:+ - * / == ~~ & | ~ ^ << <<<

string 隐式转换触发

+ 且两边大于等于 1 个string类型. 除了有 symbol类型之外

1
2
3
4
console.log(1 + '2' + '2'); // '122'
console.log(1 + +'2' + '2'); // '32'
console.log('A' - 'B' + '2'); // 'NaN2'
console.log('A' - 'B' + 2); // NaN
  1. 用 + 包裹,全部就转换为字符串后相加操作
  2. +’2’ 会先进行 number 转换,变成 1 + 2 = 3,然后遇到 + 在进行 string 转换
  3. ‘A’ - ‘B’ 会先进行 number 转换,变成 NaN,然后 string 转换
  4. 同上

四、需要注意的点

1
2
3
console.log((123).toString()); // 123
console.log(undefined.toString()); // 报错
console.log(null.toString()); // 报错

undefinednull并没有包装类,它们是基础类型,所以没有toString()方法

五、面试题

1
console.log([] == ![]); // true
  1. 一看到 == 就会想到两边会进行 Number转换
  2. Number([]) 会调用到 Array.prototype.toSting() ,得到的是一个空字符串 '' ,用Number转换后就会变成 0
  3. 右边 ![] 会先进行 Boolean 转换,[] 不是 falsey,所以Boolean([]) true
  4. !true 再进行Numebr 转换就会变成 0
  5. 所以最终就是0 == 0,结果为 true

六、奇奇怪怪的题目

1
2
3
4
66.toString() // 报错: Invalid or unexpected token
66..toString() // '66'
66.6.toString() // '66.6'
66...toString() // 报错: Unexpected token '.'