JS 类型转换机制

1. 何时触发类型转换?

JS 是动态类型语言:声明时只有一种数据类型,直到运行期间才会确定当前类型。

let x = y ? 1 : a; // x 的值编译期无法获取

虽然变量的数据类型是不确定的,但各种运算符对数据类型有要求。如果运算子的类型与预期不符,就会触发类型转换机制。

2. 显示转换常见方法

  • Number():转为数字(含 NaN)。
  • parseInt(str, radix) / parseFloat(str):解析字符串到数字,遇到非数字字符停止。
  • String():转为字符串。
  • Boolean():转为布尔值。

3. Number 转换规则

Number('123');   // 123
Number('123abc');// NaN
Number('');      // 0
Number(true);    // 1
Number(null);    // 0
Number(undefined);// NaN

4. parseInt 转换规则

相比 Number 更宽松:逐字符解析,遇到不能转换的字符就停止。

parseInt('123abc'); // 123
parseInt('12.34');  // 12
parseInt('abc');    // NaN
parseInt('10', 2);  // 2(二进制解析)

5. String 转换规则

  • 普通值调用 toString()。
  • 原始值(null / undefined / boolean / number / symbol)有包装对象方法。
  • 对象转换:先调用 Symbol.toPrimitive('string'),再 toString(),再 valueOf()。

6. Boolean 转换规则

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

7. 何时发生隐式转换?

  • 比较运算(==、!=、<、>、<=、>=)。
  • 算术运算(+、-、*、/、%、++、--)。
  • 一元运算符 +、-。

8. 隐式转换成 false 的值(Falsy)

  • undefined
  • null
  • ""(空字符串)
  • NaN
  • 0、-0、+0
  • document.all(历史遗留)

9. Symbol 值的强制类型转换

ES6 允许从符号到字符串的显式强制类型转换;隐式强制类型转换会产生错误。

  • Symbol 不能被强制类型转换为数字(显式 / 隐式都报错)。
  • Symbol 可以被强制类型转换为布尔值(结果都是 true)。
String(Symbol('a'));    // 'Symbol(a)'
Symbol('a') + '';       // TypeError
Number(Symbol('a'));    // TypeError
Boolean(Symbol('a'));   // true

10. == 操作符的强制类型转换规则

  1. 字符串和数字比较:字符串转为数字后再比较。
  2. 其他类型和布尔比较:布尔先转为数字(true → 1,false → 0)。
  3. null == undefined 为 true;其他值和它们比较都返回 false。
  4. 对象和非对象比较:对象先调用 ToPrimitive(hint 为 default → number)后再比较。
  5. 任一操作数为 NaN → false(NaN !== NaN)。
  6. 两个对象比较:必须指向同一个对象才相等。

补充:ToPrimitive 抽象操作

将对象转换为原始值时,调用 ToPrimitive(input, preferredType?)。

preferredType 可以是 number 或 string,可省略。省略时:Date 当作 string,其他值当作 number。

当 preferredType = number 时:

  1. 如果 input 是原始值,直接返回。
  2. 否则调用 input.valueOf(),若结果是原始值则返回。
  3. 否则调用 input.toString(),若结果是原始值则返回。
  4. 否则报错。

当 preferredType = string 时,步骤 2 和 3 交换。

[] + [];       // '' → 调用 ToPrimitive 得空字符串相加
[] + {};       // '[object Object]' → 双侧 toString
{} + [];       // 0 → {} 被解析为代码块,+[] 转成 0

推荐:日常开发始终使用 === / !==,避免依赖隐式转换的细节。

来源整理自:我的有道云笔记