null 与 undefined 的本质区别在于语义:undefined 是引擎自动填充的“空白格”,null 是开发者主动赋的“已清空”;判断时用 === 或 == null,处理空值优先用 ??,但需区分业务含义。

识别 null 与 undefined 的关键,不在于它们“看起来都像空”,而在于谁在说话、为什么说“空”——一个是引擎默认的静默状态,一个是开发者主动发出的明确信号。
语义本质:谁赋的值?为什么是空?
undefined 是 JavaScript 引擎自动填的“空白格”:
- 变量声明了但没赋值(let x;)
- 函数没写 return,或 return 后面没跟值(function f() {})
- 访问对象上根本不存在的属性(obj.missing)
- 调用函数时漏传参数(fn(a),但 fn 定义了两个形参)
null 是开发者亲手写的“此处清空”:
- 显式释放对象引用(user = null),协助垃圾回收
- API 返回“无结果”时的约定值(如 findUser(id) → null)
- 初始化一个将来会指向对象的变量(let cache = null)
- 表单重置、用户登出等业务动作中表示“已清空”
类型判断:别被 typeof 欺骗
typeof undefined 稳定返回 "undefined",可信;
typeof null 错误返回 "object",这是历史 bug,不能用于判断 null;
更可靠的方式是:
- 用 value === null 直接判断 null(严格相等)
- 用 value === undefined 或 typeof value === "undefined" 判断 undefined
- 需要同时排除两者时,优先用 value == null(因 null == undefined 为 true)
空值处理:何时用 ??,何时该分开判断?
空值合并运算符 ?? 只认两种值:null 和 undefined。它不关心语义,只做机械兜底:
- user?.profile?.name ?? 'Anonymous' —— 无论 profile 是 undefined(属性没定义)还是 null(被清空),链式访问断裂后都会产生 undefined,?? 都能捕获
- 0 ?? 'zero' → 0,false ?? 'no' → false,它们不是空值,不会触发 ??
但如果你需要区分“未初始化”和“已清空”,就不能只靠 ??:
- 比如表单字段:input.value 是 ''(空字符串)、undefined(尚未渲染)、还是 null(用户点过“清空”按钮)?三者业务含义不同
- 此时应分别检查:value === undefined(未就绪)、value === null(主动清空)、value === ''(用户输入为空)
TypeScript 中的类型收束实践
在类型系统里,null 和 undefined 是独立可选项,需显式纳入联合类型:
- let data: string | null; —— 表示“要么是字符串,要么是开发者设的空”
- let name: string | undefined; —— 表示“要么是字符串,要么是还没赋值/属性可能缺失”
- let user: User | null | undefined; —— 明确涵盖三种状态:有值、主动清空、尚未初始化
访问前必须做防护:
- 用可选链 user?.name 防止属性访问报错
- 用非空断言 user!.id 仅限你 100% 确定不为空时(慎用)
- 更安全的是先判断再访问:if (user != null) { ... }









