Menu Close

JavaScript 空值合并运算符

在本教程中,您将了解 JavaScript 空值合并运算符 ??,它接受两个值并在第一个值是 null 或者 undefined 时返回第二个值 。

JavaScript 空值合并运算符
JavaScript 空值合并运算符

ES2020 引入了由双问号 ?? 表示的空值合并运算符

空值合并运算符是一个接受两个值的逻辑运算符

a ?? b

由于它将 nullundefined 视为类似的情况,在本文中我们使用一个特殊的术语。为了简洁起见,我们将值称为“已定义”,当它既不是 null 也不是 undefined 时。

a ?? b 的结果是:

  • 如果 a 已定义,则返回 a;

  • 如果 a 未定义,则返回 b。

换句话说,?? 返回第一个非 null/undefined 的值,否则返回第二个。

空值合并运算符并不是什么全新的概念,它只是一个简洁的语法,用来获取两个值中的第一个“已定义”的值。

我们可以使用已经知道的运算符重写 result = a ?? b,如下所示:

result = (a !== null && a !== undefined) ? a : b;

现在应该完全清楚 ?? 的作用了。让我们看看它在哪里能够派上用场。

?? 的常见用法是提供默认值。

例如,下面的代码会显示用户的值(如果它不是 nullundefined),否则显示 “Anonymous”:

let user;

alert(user ?? "Anonymous"); // Anonymous (user is undefined)

这是一个用户已分配名字的示例:

let user = "Alice";
let userName = user ?? "Anonymous";
alert(userName); // 输出 "Alice"

我们也可以使用一系列 ?? 来从一组值中选择第一个非 null/undefined 的值。

假设我们有用户的数据存储在变量 firstNamelastNamenickName 中。如果用户没有填写对应的值,这些变量可能都是未定义的。

我们想要显示用户的名字,使用这些变量中的一个,如果它们都为 null/undefined,则显示 “Anonymous”。

我们可以使用 ?? 运算符来实现这一点:

let firstName = null;
let lastName = undefined;
let nickName = "Alice";

let userName = firstName ?? lastName ?? nickName ?? "Anonymous";
alert(userName); // 输出 "Alice"

|| 的比较

OR||运算符可以像 ?? 一样使用,正如前一章所描述的那样。

例如,在上面的代码中,我们可以将 ?? 替换为 ||,并仍然得到相同的结果:

let firstName = null;
let lastName = undefined;
let nickName = "Alice";

let userName = firstName || lastName || nickName || "Anonymous";
alert(userName); // 输出 "Alice"

然而,||?? 在处理值时略有不同。|| 会认为所有假值(如 0false""NaN 等)都需要被替换,而 ?? 只会在遇到 nullundefined 时才进行替换。

换句话说,|| 不区分 false0、空字符串 ""null/undefined,它们都是“假值”(falsy values)。如果这些中的任何一个是 || 的第一个操作数,那么我们将得到第二个操作数作为结果。

然而,在实际应用中,我们可能只希望在变量为 nullundefined 时使用默认值。也就是说,当值确实未知或未设置时。

例如,考虑以下情况:

let height = 0;

alert(height || 100); // 100
alert(height ?? 100); // 0

height || 100 会检查 height 是否为假值,而 0 确实是一个假值。所以,|| 的结果是第二个操作数,即 100

height ?? 100 会检查 height 是否为 nullundefined,而它不是这两者中的任何一个,因此结果就是 height 本身,也就是 0

在实际应用中,0 作为高度往往是一个有效的值,不应该被默认值替换。所以,?? 完全符合需求,能够做到恰到好处。

READ  脚本语言的应用场景分析

优先级

?? 运算符的优先级与 || 相同,它们在 MDN 表中的优先级都是 3

这意味着,和 || 一样,空值合并运算符 ??=? 之前进行求值,但在大多数其他运算符之后进行求值,比如 +*

因此,我们可能需要在类似以下的表达式中添加括号:

let height = null;
let width = null;

// important: use parentheses
let area = (height ?? 100) * (width ?? 50);

alert(area); // 5000

没错,如果我们省略括号,由于 * 的优先级高于 ??,乘法运算会首先执行,这会导致不正确的结果。

// without parentheses
let area = height ?? 100 * width ?? 50;

// ...works this way (not what we want):
let area = height ?? (100 * width) ?? 50;

使用 ??&&||

出于安全原因,JavaScript 禁止将 ??&&|| 运算符一起使用,除非通过括号显式指定优先级。

以下代码会触发语法错误:

let x = 1 && 2 ?? 3; // Syntax error

这个限制确实可以争论,它被添加到语言规范中是为了避免编程错误,特别是在人们从 || 转到 ?? 时。

使用显式的括号来绕过这个限制:

let x = (1 && 2) ?? 3; // Works

alert(x); // 2

短路空值合并运算符

跟逻辑或和与运算符类似,如果第一个操作数不是undefined 或者是 null ,空值合并运算符也不计算第二个值。“短路空值合并运算符” 是对 ?? 运算符的一种描述,强调它的短路特性。与其他逻辑运算符(如 &&||)一样,?? 运算符也具有短路行为,即当左侧操作数已确定结果时,右侧操作数不会被计算。

例如:

let user = null;
let userName = user ?? "Anonymous"; // user 为 null,返回 "Anonymous"
console.log(userName); // 输出 "Anonymous"

user = "Alice";
userName = user ?? "Anonymous"; // user 已定义,返回 "Alice"
console.log(userName); // 输出 "Alice"

在上面的例子中,user ?? "Anonymous" 会先检查 user 是否为 nullundefined。如果 usernullundefined,则返回默认值 "Anonymous";否则,返回 user 本身的值。所以它是一个短路操作,只有当左侧值为 nullundefined 时,右侧的默认值才会被使用。

总结

  • 空值合并运算符 ?? 提供了一种简洁的方式,从一组值中选择第一个“已定义”的值。

  • 它用于为变量赋予默认值:

    // set height=100, if height is null or undefined
    height = height ?? 100;
  • 运算符 ?? 的优先级很低,仅略高于 ?=,因此在表达式中使用时考虑添加括号。
  • 在没有显式括号的情况下,禁止将其与 ||&& 一起使用。

除教程外,本网站大部分文章来自互联网,如果有内容冒犯到你,请联系我们删除!
Posted in JavaScript 基础

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

Leave the field below empty!