跳到主要内容

转化规则(显式/隐式)怎么背?核心流程是什么?

面试速答(30 秒版 TL;DR)

  • 记一条主线:对象先 ToPrimitive(先变原始值),再按语境做 ToNumber / ToString / ToBoolean
  • 三个高频语境:
    • if/while/?:/&&/||/!:走 ToBoolean
    • +:要么字符串拼接(ToString),要么数值加法(ToNumber)
    • == / <:有一套“抽象相等/关系比较”规则,通常也会触发 ToPrimitive + ToNumber/ToString
  • 习惯:业务代码尽量用 ===,需要转换时用 Number()/String()/Boolean() 明确表达意图。

心智模型:先看“触发点”,再看“目标类型”

JS 的“类型转换”很多时候不是你主动写的,而是由操作符/语法结构触发的。

你可以按两步记:

  1. 这句代码触发了哪种“抽象操作”?(ToBoolean/ToNumber/ToString/ToPrimitive)
  2. 输入是原始值还是对象?对象一定先 ToPrimitive。

对象一定先 ToPrimitive(最容易被忽略)

很多题的关键不在 ToNumber/ToString,而在对象如何变成原始值:

  • a + ba == 1a < b:如果 a/b 是对象,都会先把对象变成原始值。

对象转原始值的完整流程见另一篇:

  • 对象转原始类型是根据什么流程运行的

ToBoolean:哪些是 falsy?

只有这些是 falsy(其余全部 truthy):

  • false
  • 0-0
  • 0n
  • ""(空字符串)
  • null
  • undefined
  • NaN

补充:document.all 在浏览器里有历史包袱,表现得像 falsy(极少考,但属于“坑点”)。


ToNumber:高频边界值(一定要会口述)

常见输入的结果(以 Number(x) 或一元 +x 为代表):

Number(null); // 0
Number(undefined); // NaN
Number(""); // 0
Number(" "); // 0
Number("1"); // 1
Number("1a"); // NaN
Number(true); // 1
Number(false); // 0

注意:Number([])0Number({})NaN,因为对象会先 ToPrimitive([] -> ""{} -> "[object Object]")。


ToString:常见输入

String(null); // "null"
String(undefined); // "undefined"
String(true); // "true"
String(1); // "1"
String(Symbol("x")); // "Symbol(x)"

注意:String(x) 能处理 Symbol,但 x + ""xSymbol 时会抛错(因为 + 的语义更复杂,可能走数值分支)。


+:到底是拼接还是加法?

二元 + 的核心口诀:

  • 两边先 ToPrimitive
  • 如果任意一边是字符串(String),走字符串拼接(另一边 ToString)
  • 否则走数值加法(两边 ToNumber)

例子:

1 + "2"; // "12"
1 + 2; // 3
true + 1; // 2
[] + 1; // "1" ([] -> "")
{} + 1; // 取决于语法位置,易踩坑(面试一般不建议用它做结论题)

==:抽象相等(会做隐式转换)

面试答题口径:

  • == 会做类型转换,规则多且容易踩坑;一般用 ===
  • == 的常见转换方向:
    • boolean 会先转数字:true -> 1false -> 0
    • stringnumber:字符串转数字再比
    • object 和原始值:对象先 ToPrimitive 再比
    • null 只和 undefined 相等:null == undefinedtrue

更系统的对照见:

  • ==和 ===有什么区别

常见追问

Q1:为什么 [] == ![]true

思路按“触发点”走:

  1. ![][] truthy,所以 ![]false
  2. [] == falsefalse -> 0[] -> "" -> 0,所以 0 == 0true

Q2:为什么 0 == !0false

见:0== !0结果是什么?为什么?