typeof null 返回 "object" 是历史遗留bug,因null底层为全零空指针,被早期32位标签机制误判为对象类型,为兼容性保留至今;正确判断需用 === null 或 Object.prototype.toString.call()。

typeof null 返回 "object" 是 JavaScript 诞生初期的实现错误,V8 等引擎沿用至今以保证向后兼容。它不是类型判断逻辑的问题,而是历史包袱——null 在底层被表示为全零的机器码,而早期 C 风格的类型判定直接把空指针当成了对象地址。
为什么 typeof 无法正确识别 null
JavaScript 的 typeof 操作符在引擎层面不走标准的 [[Type]] 内部属性检查,而是基于值的底层标记(tag)做快速分支判断。null 被标记为 NULL 类型,但最初 V8(及多数引擎)在 switch 分支中误将其归入 JS_OBJECT 分支,且该行为已写入 ECMAScript 规范附录作为“必须保持的兼容性例外”。
这不是疏忽,是权衡:若修复,大量依赖 typeof x === "object" 来检测非 null 对象的旧代码会意外失效。
安全判定原始类型的推荐方式
绕过 typeof null 陷阱的核心思路是:**先单独排除 null,再用 typeof 判定其他原始类型**。常见可靠组合如下:
-
✅ 推荐:用
Object.prototype.toString.call(x)—— 它对所有值返回规范字符串(如[object Null]、[object String]),无歧义,且可区分 Object、Array、Date 等; -
✅ 实用:组合判断
x === null ? "null" : typeof x—— 简洁高效,覆盖 null、undefined、boolean、number、string、symbol、bigint; -
❌ 避免:仅靠
typeof x === "object"判断是否为对象 —— 它对 null、数组、正则、日期等都返回 true,语义模糊。
现代开发中的实际取舍
在 TypeScript 或强约束环境中,null 通常被显式排除(如 string | number 不含 null),此时 typeof 可放心使用。但在运行时类型校验(如工具函数、序列化逻辑)中,必须主动处理 null。
例如写一个通用类型名获取函数:
function getRawType(value) {
if (value === null) return "null";
if (value === undefined) return "undefined";
return typeof value;
}
这个函数比 typeof 多两行,却彻底规避了历史 Bug 的干扰。

















