2023 年 4 月 23 日

空值合并运算符“??”

最近添加
这是最近添加到该语言中的内容。旧浏览器可能需要填充代码

空值合并运算符写成两个问号??

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

a ?? b的结果是

  • 如果a已定义,则为a
  • 如果a未定义,则为b

换句话说,??如果第一个参数不是null/undefined,则返回第一个参数。否则,返回第二个参数。

空值合并运算符并不是什么完全新颖的东西。它只是一种获取两个值中第一个“已定义”值的好语法。

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

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

现在应该完全清楚??的作用了。让我们看看它在哪些地方有帮助。

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

例如,这里我们显示user(如果其值不是null/undefined),否则显示匿名

let user;

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

下面是将 user 分配给名称的示例

let user = "John";

alert(user ?? "Anonymous"); // John (user is not null/undefined)

我们还可以使用一系列 ?? 从列表中选择第一个不是 null/undefined 的值。

假设我们在变量 firstNamelastNamenickName 中有用户数据。如果用户决定不填写相应的值,则所有这些值都可能未定义。

我们希望使用其中一个变量显示用户名,或者如果所有变量都是 null/undefined,则显示“匿名”。

让我们为此使用 ?? 运算符

let firstName = null;
let lastName = null;
let nickName = "Supercoder";

// shows the first defined value:
alert(firstName ?? lastName ?? nickName ?? "Anonymous"); // Supercoder

与 || 比较

OR || 运算符可以与 ?? 以相同的方式使用,如 前一章 所述。

例如,在上面的代码中,我们可以用 || 替换 ??,并且仍然获得相同的结果

let firstName = null;
let lastName = null;
let nickName = "Supercoder";

// shows the first truthy value:
alert(firstName || lastName || nickName || "Anonymous"); // Supercoder

从历史上看,OR || 运算符首先出现。它从 JavaScript 诞生之初就存在,因此开发人员长期以来一直将其用于此类目的。

另一方面,空值合并运算符 ?? 最近才添加到 JavaScript 中,原因是人们对 || 不太满意。

它们之间的重要区别在于

  • || 返回第一个真值
  • ?? 返回第一个已定义的值。

换句话说,|| 不区分 false0、空字符串 ""null/undefined。它们都是相同的——假值。如果其中任何一个是 || 的第一个参数,那么我们将获得第二个参数作为结果。

然而,在实践中,我们可能只希望在变量为 null/undefined 时才使用默认值。也就是说,当值确实未知/未设置时。

例如,考虑这一点

let height = 0;

alert(height || 100); // 100
alert(height ?? 100); // 0
  • height || 100 检查 height 是否为假值,而它为 0,确实为假。
    • 因此,|| 的结果是第二个参数 100
  • height ?? 100 检查 height 是否为 null/undefined,但它不是,
    • 因此,结果是“原样”的 height,即 0

在实践中,零高度通常是一个有效值,不应替换为默认值。因此,?? 做了正确的事情。

优先级

?? 运算符的优先级与 || 相同。它们在 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

总结

  • 空值合并运算符 ?? 提供了一种从列表中选择第一个“已定义”值的方法。

    它用于为变量分配默认值

    // set height=100, if height is null or undefined
    height = height ?? 100;
  • 运算符 ?? 的优先级非常低,仅比 ?= 高一点,因此在表达式中使用它时考虑添加括号。

  • 禁止在没有显式括号的情况下将它与 ||&& 一起使用。

教程地图

评论

在评论之前阅读此内容…
  • 如果您有改进建议 - 请 提交 GitHub 问题 或提交拉取请求,而不是评论。
  • 如果您无法理解文章中的某些内容 – 请详细说明。
  • 要插入几行代码,请使用 <code> 标签,对于多行 – 将它们包装在 <pre> 标签中,对于超过 10 行 – 使用沙箱(plnkrjsbincodepen…)