typeof null 返回 "object" 是因底层类型标签机制将全零的 null 误判为对象,该行为自1995年沿用至今,为兼容性被规范强制保留。

这确实是个“一眼反直觉、深挖有故事”的问题:null 明明是原始值,typeof null 却返回 "object"。它不是疏漏,也不是新 bug,而是 JavaScript 诞生第 10 天就埋下的、被规范固化的历史实现细节。
底层类型标签机制误判全零值
1995 年 Brendan Eich 在 Netscape 实现 JS 原型时,用 32 位字(word)存储值,其中最低几位作为类型标签(type tag):
- 000 → 对象(object),表示该值是一个指向堆内存的指针
- 001 → 整数(integer)
- 010 → 浮点数(double)
- 100 → 字符串(string)
- 110 → 布尔值(boolean)
null 被定义为“空指针”,在 C 风格实现中直接用全零机器码 0x00000000 表示。当 typeof 检查其低三位时,得到的是 000 —— 和对象完全一致。解释器没给 null 单独设分支,直接归入 object 分支。
规范将错误行为写成强制要求
这个判断逻辑在 JavaScript 1.1(1996)中已落地,随后被写入 ECMA-262 第一版(1997)。尽管 ES6 明确将 null 定义为原始类型,但规范附录明确指出:typeof null 必须返回 "object",这是“必须保持的兼容性例外”。
- TC39 曾评估修复提案(ECMA issue #495),结论是风险远超收益
- 大量旧代码依赖
typeof x === "object"做粗略对象过滤,若突然变"null",会触发静默逻辑错误 - 这不是“忘了修”,而是权衡后主动选择的“wontfix”
技术事实与语义现实的割裂
这个返回值和 null 的真实性质完全冲突:
-
null instanceof Object→ false -
Object.getPrototypeOf(null)→ 报错:"Cannot convert undefined or null to object" -
null.toString()→ 报错:"Cannot read properties of null"
这些行为一致表明:null 不具备任何对象特征。它只是被 typeof 的底层标签读取逻辑“张冠李戴”了——误把内存表示当成了语义类型。
为什么至今不改:兼容性锁死
到 2026 年,这个行为已稳定运行近 30 年。全球数以亿计的网页、框架、构建工具都隐式或显式依赖它。哪怕只是让 typeof null 在严格模式下返回 "null",也会导致:
- 条件判断失效(如
if (typeof obj === "object") { ... }突然跳过 null 分支) - 类型守卫逻辑崩溃(尤其在未加
&& obj !== null的旧代码中) - 前端监控、序列化、ORM 映射等基础设施出现边缘 case 异常
语言设计者最终认定:维持这个“错误”,比修复它更安全、更务实。

















