空值合并运算符写成两个问号??
。
由于它以类似的方式处理null
和undefined
,因此我们将在本文中使用一个特殊术语。为了简洁起见,当一个值既不是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
的值。
假设我们在变量 firstName
、lastName
或 nickName
中有用户数据。如果用户决定不填写相应的值,则所有这些值都可能未定义。
我们希望使用其中一个变量显示用户名,或者如果所有变量都是 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 中,原因是人们对 ||
不太满意。
它们之间的重要区别在于
||
返回第一个真值。??
返回第一个已定义的值。
换句话说,||
不区分 false
、0
、空字符串 ""
和 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;
-
运算符
??
的优先级非常低,仅比?
和=
高一点,因此在表达式中使用它时考虑添加括号。 -
禁止在没有显式括号的情况下将它与
||
或&&
一起使用。
评论
<code>
标签,对于多行 – 将它们包装在<pre>
标签中,对于超过 10 行 – 使用沙箱(plnkr,jsbin,codepen…)