Menu

JavaScript null 和 undefined 的区别、判断方法与用法

JavaScript 中 null 和 undefined 到底有什么区别,如何判断它们,以及在自己的代码里该用哪一个。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

表示“没有”的两种方式

大多数语言只用一个值表示“不存在”。JavaScript 有两个:null 和 undefined。它们的行为相似到足以让初学者困惑,又不同到足以让有经验的开发者踩坑。花十分钟弄清楚两者的区别,非常值得。

简单来说:

  • undefined 是 JavaScript 在某样东西缺失时给你的值。
  • null 是你想表达“故意留空”时写下的值。

注意其中的规律:上面每一个 undefined 都是因为 JavaScript 找不到值。而 null 出现,是因为有人把它写了进去。

undefined 从哪里来

undefined 只在几种特定情况下出现,都是“没有可用的值”的不同形式:

每种情况下,JavaScript 都去取一个值,结果什么都没找到。undefined 就是引擎在告诉你:“我找过了,没有值。”

你可以自己赋值 undefined(let x = undefined;),但不应该这么做。让它保持“JavaScript 什么都没找到”这个信号。当做决定的是你自己时,就用 null。

null 从哪里来

null 只有在有人写下它时才会出现。这正是它的意义所在:它是一个有意的标记。

DOM API 经常使用 null:document.getElementById("missing") 返回的是 null 而不是 undefined,因为浏览器在明确告诉你“我找过了,答案是没有这个元素”。JSON.parse("null") 也会得到 null,JSON 中没有 undefined。

可以这样理解:undefined 是默认的缺失,null 是选择的缺失。

typeof 的怪现象

这是那个著名的问题:

typeof null 返回 "object" 是 1995 年留下的 bug,修复它会破坏现有网站,所以就被永远保留了下来。null 不是对象,它是原始值,和 undefined、数字、字符串、布尔值一样。只是 typeof 的结果在这里说了谎。

实际影响是:typeof 无法用来检测 null。要直接比较:

或者更常见的做法是一次同时判断两者,见下一节。

同时判断两者:== null 惯用写法

大多数时候你并不关心手上的是哪一种缺失值,只想在使用前知道某个值是否缺失。惯用的判断方式是与 null 做宽松相等比较:

value == null 只对 null 和 undefined 为 true,对其他所有值都为 false,包括 0、"" 和 false,这通常正是你想要的。这是唯一一种更推荐用 == 而不是 === 的情况。代码检查工具也知道这一点,会允许这种写法。

如果你想写得更明确,value === null || value === undefined 意思完全相同,读起来也很清楚。

空值运算符:?? 和 ?.

有两个运算符是专门为了方便处理 null 和 undefined 而加入的。它们对这两个值一视同仁,对其他值则不做任何处理。

空值合并(??)只在左侧为 null 或 undefined 时才提供后备值:

对比一下 ||:它会把 0 替换成 3,因为 0 是假值。?? 更严格,只对这两个空值生效。

可选链(?.)在遇到 null 或 undefined 时停止对属性链求值,并返回 undefined:

这两个运算符之所以存在,是因为“这个值是不是空值?”这个问题太常见了。教程后面会深入讲解它们。

默认参数只对 undefined 生效

一条不起眼但很重要的规则:默认参数值只在 undefined 时生效,null 不会触发。

传入 null 会被视为“我明确选择了没有值”,并原样保留。如果你希望 null 也能触发后备值,就在函数内部使用 ??:

这个区别经常让人犯错。默认值处理的是缺失的参数;?? 处理的是空值参数。

JSON 和消失的 undefined

JSON 有 null,却没有 undefined。这会在序列化时带来无声的意外:

age 字段整个消失了:JSON.stringify 会丢弃值为 undefined 的属性。null 被保留下来,因为 JSON 支持它。把对象经过 JSON 来回转换一次,是 undefined 属性悄悄消失的常见原因。

在数组中,undefined 会变成 null:

如果你在设计 API 的数据格式,表示“没有值”的字段优先用 null 而不是 undefined。它能完整地传过去。

什么时候用哪个

在自己的代码中,一个合理的约定是:

  • 让 undefined 表示“没有提供”:缺失的参数、未赋值的变量、不存在的属性。不要手动赋值 undefined。
  • 想明确表达“这里是故意留空”时用 null:已退出登录的用户、未选中的选项、已清空的表单字段。
  • 在 API 边界上两者都接受(用 == null 或 ??),但对于你产生的值,要保持一致。

有些风格指南(包括 TypeScript 的)完全不用 null,只用 undefined。这也有道理:一个值比两个值简单。每个项目定一条规则,然后处处遵守。

下一章:类型转换

当 JavaScript 把 null 和 undefined 转换成数字、字符串或布尔值时,它们有各自特定的行为:Number(null) 是 0,而 Number(undefined) 是 NaN,这种不对称会造成真实的 bug。下一章讲类型转换,看完完整的规则后,JavaScript 的很多怪现象就不再神秘了。

常见问题

JavaScript 中 null 和 undefined 有什么区别?

undefined 表示一个值还没有被赋值,变量没赋值、参数没传或对象属性不存在时,JavaScript 给你的就是它。null 是你特意赋上的“这里没有值”。JavaScript 自己从不产生 null,必须由你写出来。

如何同时判断 null 和 undefined?

用 value == null。宽松相等把 null 和 undefined 视为彼此相等,但与其他任何值都不相等,所以 x == null 只对这两个值为 true。这是唯一一个用 == 而不用 === 既地道又安全的地方。

为什么 typeof null 返回 'object'?

这是 JavaScript 第一个版本就存在的 bug,修复它会破坏现有的网页,所以一直没改。尽管 null 是原始值,typeof null 仍然返回 'object'。要专门判断 null,直接比较:value === null。

在自己的代码里应该用 null 还是 undefined?

让 undefined 表示“没有提供”,在想明确表达“这里是故意留空”时用 null。很多代码库(以及 TypeScript 的风格指南)完全不用 null,只用 undefined。每个项目选定一种约定,然后坚持下去。

Coddy 编程语言插图

和 Coddy 一起学编程

开始