[1-3] 隐式类型转换 · 常见规则与 [] == ![] 等例子

4 阅读3分钟

所属板块:1. 数据类型与内存机制

记录日期:2026-03-xx
更新:根据遇到的新奇葩题补充

1. 为什么会有隐式类型转换?

JavaScript 在某些操作符(==、+、if 判断等)下,会自动把操作数转换成其他类型。
这是语言设计导致的“便利”,但也制造了很多坑。
记住:生产代码里能用 === 就用 ===,尽量避免隐式转换带来的意外。

2. 常见触发隐式转换的场景

  1. 比较运算符 ==(不严格相等,会转换)
  2. 加号 +(字符串拼接优先,其余转数字相加)
  3. if / 三元 / 逻辑运算(转为布尔值)
  4. 数学运算(- * / %)(两边都转成数字)
  5. 对象参与运算时(会调用 ToPrimitive)

3. 转布尔值的规则(if 判断、!!、三元等)

只有以下 6 个值转为 false,其余全为 true:

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

常见反直觉例子:

if ([])          { console.log("[] 为 true") }     // 通过
if ({})          { console.log("{} 为 true") }     // 通过
if ("0")         { console.log("\"0\" 为 true") }  // 通过
if (new Date())  { console.log("Date 对象为 true") } // 通过

4. == 的转换规则(最容易出问题的)

== 的转换优先级大致是:

  1. 如果两边都是 null 或 undefined → true
  2. 如果一边是 null/undefined,另一边不是 → false
  3. 如果两边都是原始类型 → 都转成数字比较(字符串转数字,布尔转 0/1)
  4. 如果有一边是对象 → 对象调用 ToPrimitive(优先 valueOf → toString)
  5. 如果两边都是对象 → 比较是否同一引用

经典例子汇总:

console.log(0 == "0");          // true   (字符串 "0" 转数字 0)
console.log(0 == false);        // true   (false 转 0)
console.log("" == false);       // true   ("" 转 0,false 转 0)
console.log([] == ![]);         // true   ← 经典题

// [] == ![] 拆解:
![]          → false           (数组转布尔为 true,取反为 false)
[] == false  → [] 转成 ""(空字符串) → "" == false""0false00 == 0true

另一个变态组合:

console.log([] == 0);           // true   ([] → "" → 0)
console.log([] == "");          // true   ([] → "")
console.log([[]] == "");        // false  ([[]] → "0" → 不等于 "")
console.log({} == "[object Object]"); // false ({} → "[object Object]" 但不等于字符串本身)

5. + 号的特殊行为

  • 是唯一一个既能做数学加法又能做字符串拼接的运算符,规则:
  • 只要有一边是字符串 → 都转成字符串拼接
  • 两边都不是字符串 → 都转成数字相加
console.log(1 + "2");         // "12"
console.log(1 + +"2");        // 3      (+"2" 强制转数字)
console.log([] + {});         // "[object Object]"   ([] → "",{} → "[object Object]")
console.log({} + []);         // 0      ({} 被当成代码块,+[] → 0)
console.log(1 + {});          // "1[object Object]"

6. 对象转原始类型(ToPrimitive)过程

当对象参与 ==、+ 等操作时,会按以下顺序尝试转换:

  1. 如果有 [Symbol.toPrimitive] 方法 → 调用它
  2. 否则调用 valueOf()
  3. 否则调用 toString()
  4. 如果还不行 → TypeError

示例:

const obj = {
  valueOf() { return 42; },
  toString() { return "hello"; }
};

console.log(obj + 1);         // 43     (优先 valueOf)
console.log("" + obj);        // "hello"(+ 字符串时优先 toString? 其实还是 valueOf 先)

// 更准确:+ 号两边原始类型不同时,先 ToPrimitive 再决定

7. 小结 & 实际使用建议

  • 永远优先用 ===,除非你明确知道要利用转换(极少情况)
  • 面试/刷题时,记住 [] == ![]、{} + []、[] + {} 这三组经典组合的答案
  • 日常写代码遇到不确定类型时,先用 getType()(上一篇文章封装的)打印出来,再决定怎么处理

下一篇文章会记录内存机制、垃圾回收和常见内存泄漏场景。

返回总目录:戳这里