undefined 和 nullundefined 与 nullundefined 和 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;
assert.equal(myVar, undefined);未提供参数 x
function func(x) {
return x;
}
assert.equal(func(), undefined);缺少属性 .unknownProp
const obj = {};
assert.equal(obj.unknownProp, undefined);如果我们没有通过 return 语句显式指定函数的结果,JavaScript 会为我们返回 undefined
function func() {}
assert.equal(func(), undefined);null 的出现对象的原型要么是一个对象,要么是在原型链的末端,是 null。Object.prototype 没有原型
> Object.getPrototypeOf(Object.prototype)
null如果我们将正则表达式(例如 /a/)与字符串(例如 'x')匹配,我们将获得一个包含匹配数据的对象(如果匹配成功)或 null(如果匹配失败)
> /a/.exec('x')
nullJSON 数据格式 不支持 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;以下两个表达式是等效的
a ?? b
a !== undefined && a !== null ? a : b以下代码展示了一个真实的例子
function countMatches(regex, str) {
const matchResult = str.match(regex); // null or Array
return (matchResult ?? []).length;
}
assert.equal(
countMatches(/a/g, 'ababa'), 3);
assert.equal(
countMatches(/b/g, 'ababa'), 2);
assert.equal(
countMatches(/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'},
];
assert.deepEqual(
files.map(f => getTitle(f)),
['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]??= 是一个 逻辑赋值运算符。以下两个表达式大致等效
a ??= b
a ?? (a = b)这意味着 ??= 是 短路的:只有当 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) {
book.title ??= '(Untitled)';
}
assert.deepEqual(
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({})
undefinedundefined 和 null 的历史在 Java 中(它启发了 JavaScript 的许多方面),初始化值取决于变量的静态类型
null 初始化。int 变量使用 0 初始化。在 JavaScript 中,每个变量都可以保存对象值和基本类型值。因此,如果 null 表示“不是对象”,那么 JavaScript 还需要一个初始化值来表示“既不是对象也不是基本类型值”。该初始化值是 undefined。
测验
参见 测验应用程序。