null 表示业务明确的空值,undefined 表示未定义或缺失;null 需显式赋值,undefined 是语言默认值;接口字段存在但为空用 null,字段可能缺失用 undefined;类型声明须严格对应协议约定。

null 表示“有意为之的空值”,即业务上明确知道这里该是空、不该有数据;undefined 表示“未定义”,即变量/属性/返回值尚未被赋值或根本不存在,属于运行时状态,不是业务意图。
区分赋值场景:什么时候该用 null,什么时候只能是 undefined
JavaScript 中 undefined 是语言默认值:未初始化的变量、无返回值函数、对象缺失属性、函数参数未传入,都会自然得到 undefined。你不能也不该手动把它当作“业务空值”来用。
null 必须显式赋值,它是一个可读性强、语义清晰的占位符。比如用户主动取消上传,后端返回 { avatar: null },表示“确认无头像”,而不是“忘了填头像字段”。
- 接口响应中表示“该字段存在但值为空” → 用
null - 函数参数可选但调用者没传 → 留作
undefined,别提前转成null - 组件 props 初始化时不确定是否有值 → 初始设为
undefined,加载后根据业务逻辑决定赋null或具体值
判断逻辑别混用:== null 不安全,=== null 和 === undefined 才可靠
== null 会同时匹配 null 和 undefined,看似省事,实则掩盖语义差异。比如一个表单字段允许空字符串、0、false,又允许“未填写”,这时 value == null 会把 0 也误判为“未填写”。
真正需要区分语义时,必须分开判断:
if (user.profile === null) {
// 明确知道 profile 被设为空,比如用户删掉了资料
} else if (user.profile === undefined) {
// profile 字段压根没从接口拿到,可能接口出错或字段未开放
}
- 用
??(空值合并)处理null和undefined共同兜底 → 合理,因为两者都代表“无有效值” - 用
?.profile?.name安全访问嵌套属性 → 内部依赖undefined的传播机制,和null无关 - 避免
!value判断,它会把0、''、false全吞掉
TypeScript 中类型声明要反映真实语义,别偷懒写 string | undefined 代替 string | null
如果 API 明确可能返回 "name": null,类型就该是 name: string | null;如果字段完全可能缺失(如某些用户没填邮箱),才是 email?: string(等价于 email: string | undefined)。
混用会导致类型检查失效:比如你写了 email?: string,但后端实际返回 {"email": null},TS 不报错,运行时却拿到 null,后续 .toLowerCase() 就崩了。
- 后端字段存在但值为
null→ 类型加| null - 后端字段可能完全不出现 → 用
?可选修饰符(生成| undefined) - 想强制区分“空”和“未设置”,可用联合类型
string | null | undefined,但要清楚每种分支对应什么业务路径
最常被忽略的一点:后端 JSON 序列化时,null 会被保留,undefined 会被直接丢弃。这意味着你看到接口文档里写了 "avatar": null,前端就必须用 null 接收;如果文档写的是“字段可能不存在”,那就要按 undefined 处理——不能靠经验猜,得看协议约定。









