undefined
和 null
undefined
与 null
undefined
和 null
的出现undefined
的出现null
的出现undefined
或 null
??
) 用于默认值 [ES2020]||
) 为默认值??=
) [ES2021]undefined
和 null
没有属性undefined
和 null
的历史许多编程语言都有一个称为 null
的“非值”。它表示变量当前没有指向任何对象 - 例如,当它尚未初始化时。
相比之下,JavaScript 有两个这样的值:undefined
和 null
。
undefined
与 null
这两个值非常相似,并且经常可以互换使用。因此,它们之间的区别很微妙。语言本身做了如下区分
undefined
表示“未初始化”(例如,变量)或“不存在”(例如,对象的属性)。null
表示“有意不存在任何对象值”(引自 语言规范)。程序员可以做如下区分
undefined
是语言使用的非值(当某些内容未初始化等时)。null
表示“显式关闭”。也就是说,它有助于实现一种类型,该类型既包含有意义的值,也包含表示“没有有意义的值”的元值。这种类型在函数式编程中称为 选项类型 或 可能类型。undefined
和 null
的出现以下小节描述了 undefined
和 null
在语言中出现的位置。我们将遇到几种机制,这些机制将在本书后面详细解释。
undefined
的出现未初始化的变量 myVar
let myVar;
.equal(myVar, undefined); assert
未提供参数 x
function func(x) {
return x;
}.equal(func(), undefined); assert
缺少属性 .unknownProp
const obj = {};
.equal(obj.unknownProp, undefined); assert
如果我们没有通过 return
语句显式指定函数的结果,JavaScript 会为我们返回 undefined
function func() {}
.equal(func(), undefined); assert
null
的出现对象的原型要么是一个对象,要么是在原型链的末端,是 null
。Object.prototype
没有原型
> Object.getPrototypeOf(Object.prototype)null
如果我们将正则表达式(例如 /a/
)与字符串(例如 'x'
)匹配,我们将获得一个包含匹配数据的对象(如果匹配成功)或 null
(如果匹配失败)
> /a/.exec('x')null
JSON 数据格式 不支持 undefined
,只支持 null
> JSON.stringify({a: undefined, b: null})'{"b":null}'
undefined
或 null
检查两者
if (x === null) ···
if (x === undefined) ···
x
是否有值?
if (x !== undefined && x !== null) {
// ···
}if (x) { // truthy?
// x is neither: undefined, null, false, 0, NaN, ''
}
x
是 undefined
还是 null
?
if (x === undefined || x === null) {
// ···
}if (!x) { // falsy?
// x is: undefined, null, false, 0, NaN, ''
}
真值 表示“如果强制转换为布尔值,则为 true
”。假值 表示“如果强制转换为布尔值,则为 false
”。这两个概念在 §15.2 “假值和真值” 中有详细解释。
??
) 用于默认值 [ES2020]有时我们接收一个值,并且只希望在它不是 null
或 undefined
时才使用它。否则,我们希望使用默认值作为备用。我们可以通过 *空值合并运算符* (??
) 来做到这一点
const valueToUse = receivedValue ?? defaultValue;
以下两个表达式是等效的
?? b
a !== undefined && a !== null ? a : b a
以下代码展示了一个真实的例子
function countMatches(regex, str) {
const matchResult = str.match(regex); // null or Array
return (matchResult ?? []).length;
}
.equal(
assertcountMatches(/a/g, 'ababa'), 3);
.equal(
assertcountMatches(/b/g, 'ababa'), 2);
.equal(
assertcountMatches(/x/g, 'ababa'), 0);
如果在 str
中有一个或多个 regex
的匹配项,则 .match()
返回一个数组。如果没有匹配项,它会返回 null
(而不是空数组)。我们通过 ??
运算符来解决这个问题。
我们也可以使用 可选链
return matchResult?.length ?? 0;
function getTitle(fileDesc) {
return fileDesc.title ?? '(Untitled)';
}
const files = [
path: 'index.html', title: 'Home'},
{path: 'tmp.html'},
{;
].deepEqual(
assert.map(f => getTitle(f)),
files'Home', '(Untitled)']); [
在某些情况下,解构也可以用于默认值 - 例如
function getTitle(fileDesc) {
const {title = '(Untitled)'} = fileDesc;
return title;
}
||
) 为默认值在 ECMAScript 2020 和空值合并运算符之前,逻辑或用于默认值。这有一个缺点。
||
对于 undefined
和 null
来说工作正常
> undefined || 'default''default'
> null || 'default''default'
但它也会为所有其他假值返回默认值 - 例如
> false || 'default''default'
> 0 || 'default''default'
> 0n || 'default''default'
> '' || 'default''default'
将其与 ??
的工作方式进行比较
> undefined ?? 'default''default'
> null ?? 'default''default'
> false ?? 'default'false
> 0 ?? 'default'0
> 0n ?? 'default'0n
> '' ?? 'default'''
??=
) [ES2021]??=
是一个 逻辑赋值运算符。以下两个表达式大致等效
??= b
a ?? (a = b) a
这意味着 ??=
是 短路的:只有当 a
为 undefined
或 null
时才会进行赋值。
??=
添加缺少的属性const books = [
{isbn: '123',
,
}
{title: 'ECMAScript Language Specification',
isbn: '456',
,
};
]
// Add property .title where it’s missing
for (const book of books) {
.title ??= '(Untitled)';
book
}
.deepEqual(
assert,
books
[
{isbn: '123',
title: '(Untitled)',
,
}
{title: 'ECMAScript Language Specification',
isbn: '456',
,
}; ])
undefined
和 null
没有属性undefined
和 null
是仅有的两个 JavaScript 值,如果我们尝试读取它们的属性,就会得到一个异常。为了探究这种现象,让我们使用以下函数,该函数读取(“获取”)属性 .foo
并返回结果。
function getFoo(x) {
return x.foo;
}
如果我们将 getFoo()
应用于各种值,我们可以看到它只对 undefined
和 null
失败
> getFoo(undefined)TypeError: Cannot read properties of undefined (reading 'foo')
> getFoo(null)TypeError: Cannot read properties of null (reading 'foo')
> getFoo(true)undefined
> getFoo({})undefined
undefined
和 null
的历史在 Java 中(它启发了 JavaScript 的许多方面),初始化值取决于变量的静态类型
null
初始化。int
变量使用 0
初始化。在 JavaScript 中,每个变量都可以保存对象值和基本类型值。因此,如果 null
表示“不是对象”,那么 JavaScript 还需要一个初始化值来表示“既不是对象也不是基本类型值”。该初始化值是 undefined
。
测验
参见 测验应用程序。