相关于JavaScript中是否有"空合并"运算符? - JavaScript现在具有??
运算符,我经常看到它被使用。以前,大多数JavaScript代码使用||
。
let userAge = null
// These values will be the same.
let age1 = userAge || 21
let age2 = userAge ?? 21
在什么情况下,
??
和||
会有不同的行为?相关于JavaScript中是否有"空合并"运算符? - JavaScript现在具有??
运算符,我经常看到它被使用。以前,大多数JavaScript代码使用||
。
let userAge = null
// These values will be the same.
let age1 = userAge || 21
let age2 = userAge ?? 21
??
和||
会有不同的行为?逻辑或运算符||
在左值为falsy值时使用右值,而空值合并运算符??
在左值为null
或undefined
时使用右值。
这些运算符经常用于在第一个值缺失时提供默认值。
但是如果你的左值可能包含""
、0
或false
(因为这些是falsy值),那么逻辑或运算符||
可能会有问题:
console.log(12 || "not found") // 12
console.log(0 || "not found") // "not found"
console.log("jane" || "not found") // "jane"
console.log("" || "not found") // "not found"
console.log(true || "not found") // true
console.log(false || "not found") // "not found"
console.log(undefined || "not found") // "not found"
console.log(null || "not found") // "not found"
在许多情况下,你可能只想在左侧的值为null
或undefined
时获取右侧的值。这就是空值合并运算符??
的作用:
console.log(12 ?? "not found") // 12
console.log(0 ?? "not found") // 0
console.log("jane" ?? "not found") // "jane"
console.log("" ?? "not found") // ""
console.log(true ?? "not found") // true
console.log(false ?? "not found") // false
console.log(undefined ?? "not found") // "not found"
console.log(null ?? "not found") // "not found"
当前LTS版本的Node(v10和v12)中不支持??
操作符,但是您可以在某些TypeScript或Node版本中使用:
??
操作符于2019年11月添加到TypeScript 3.7中。
最近,??
运算符被包含在ES2020中,由Node 14支持(在2020年4月发布)。
当支持nullish coalescing操作符??
时,通常会使用它代替OR操作符||
(除非有充分的理由不这样做)。
空值合并运算符 ??
区分以下两种情况:
null
,undefined
)false
,0
,''
等等)||
(逻辑或)对这两种情况都视为相同。
我创建了一个简单的图形来说明 JavaScript 中 空值 和 假值 之间的关系:
let x, y
x = 0
y = x || 'default' // y = 'default'
y = x ?? 'default' // y = 0
??
和||
之间的区别在于一个检查nullish值,而另一个检查falsey值。然而,有许多情况下它们的行为是相同的。这是因为在JavaScript中,每个nullish值也是falsey的(但并不是每个falsey值都是nullish)。let y
y = false || 'default' // y = 'default'
y = false ?? 'default' // y = false
y = 0n || 'default' // y = 'default'
y = 0n ?? 'default' // y = 0n
y = NaN || 'default' // y = 'default'
y = NaN ?? 'default' // y = NaN
y = '' || 'default' // y = 'default'
y = '' ?? 'default' // y = ''
??
而不是||
。let y
y = null || 'default' // y = 'default'
y = null ?? 'default' // y = 'default'
y = undefined || 'default' // y = 'default'
y = undefined ?? 'default' // y = 'default'
作为一个非常简短的规则,你可以把它看成相反的方式:
||
(或)返回第一个“真值”
(如果没有“真值”,则返回最后一个值)??
(nullish coalescing)返回第一个“已定义”值
(如果没有“已定义”值,则返回最后一个值)示例
x = false || true; // --> true (the first 'truthy' value - parameter 2)
x = false ?? true; // --> false (the first 'defined' value - parameter 1)
还有在您提供的问题的答案中也有相关说明:与逻辑或 (
||
) 操作符相反,如果左操作数是一个假值,但不是null
或undefined
,则返回左操作数。换句话说,如果您使用||
为另一个变量foo
提供一些默认值,则如果您将某些假值视为可用 (例如''
或0
),则可能会遇到意外的行为。请参见下面的更多示例。
Regardless of the type of the first operand, if casting it to a Boolean results in false, the assignment will use the second operand. Beware of all the cases below:
alert(Boolean(null)); // false alert(Boolean(undefined)); // false alert(Boolean(0)); // false alert(Boolean("")); // false alert(Boolean("false")); // true -- gotcha! :)
基于MDN文档:
与逻辑或(||)运算符相反,如果左操作数是一个假值,但不是
null
或undefined
,该值将被返回。
概念示例:
When use ||
for a falsy value that is NOT undefined
or null
:
false || 'name'; // ==> the 'name' is returned
But when using ??
for above case:
false ?? 'name'; // ==> the false is returned
真实例子:
假设我们有一个phone
变量,在我们的表单中不是必需的,空字符串(''
)对我们来说是有效的,如果phone
变量为null
或undefined
,我们想要执行doSomething()
,现在猜猜看:
When use ||
for a falsy value that is NOT undefined
or null
:
const phone = ''; // assume it became empty string from some action
phone || doSomething(); // ==> damn, the doSomething is run
// but we want to run it if it's `undefined` or `null` the empty string is valid for us
But when using ??
for above case:
const phone = ''; // same assumption like above
phone ?? doSomething(); // ==> yeah, that's right
// the empty string is valid for us and the doSomething is not run
注意: 实际上这只是一个例子,在实际项目中您可以更好地感受到这个可爱的操作用法。
注意: 对于undefined
或null
,它们两者的行为都相同。
当 ||
作为一个布尔条件用于判断时,会返回 false。例如:
let userAge = false
// These values will be the same.
let age1 = userAge || 21 // 21
let age2 = userAge ?? 21 // false
function f(input) {
const val = input || 1;
return 41 + val;
}
function g(input) {
const val = input ?? 1;
return 41 + val;
}
console.log("using ||:", f(0));
console.log("using ??:", g(0));
console.log(null ?? "nullish");
console.log(undefined ?? "nullish");
console.log("" ?? "nullish");
console.log(0 ?? "nullish");
console.log(false ?? "nullish");
console.log(null || "falsy");
console.log(undefined || "falsy");
console.log("" || "falsy");
console.log(0 || "falsy");
console.log(false || "falsy");
以下是关于如何确定需要哪种操作符的几条规则。最简单的测试:
null
(和undefined
- 通常是同一件事)吗?那就用??
。如果你不确定,最好使用 nullish coalescing 操作符。0
或""
,例如吗?那就用||
。第二个就比较麻烦了。你怎么知道你需要丢弃 falsy 值呢?第一个代码片段展示了如果这样做会发生什么: f(0)
会丢弃零,从而产生不同的结果。这是一个有些常见的 bug 来源。由于构造a = b || c
常用于引入回退值(在这种情况下为c
),因此它可能会在你不想要的时候意外回退到它。
function updateAge(years) {
var yearsToAdd = years || 1;
return this.age + yearsToAdd
}
如果您想提供 updateAge()
(无参数) 的回退,那么这将起作用,但如果您调用 updateAge(0)
(不更新),则会失败。同样的,您可以有:
function sayMyName(greeting) {
var prefix = greeting || "Hello, my name is ";
return prefix + this.firstName;
}
同样,这对于sayMyName()
(没有参数)有效,但是对于sayMyName("")
(明确无欢迎语)则失败。
一般来说,如果您提供的默认值与假值不同,那么您可能会遇到问题。但是,如果您的默认值是假值- num || 0
或str || ""
- 那么实际上并不重要。
很少(或者应该很少)预期混合类型(数字、字符串、对象等)并为其提供回退: input || fallback
是有效的,但将拒绝空字符串和零。除非您明确不想要其中任何一个,否则通常都会出现问题。
简而言之,您应该始终使用 nullish 合并运算符 ??
。这将减轻记忆负担以确定它是否可能是错误的。也没有太多理由避免它。它比布尔 OR 新,因此在旧环境中不起作用,但是现在您可能应该为这些转译代码。如果您不能或不想这样做,则别无选择,应该使用布尔 OR。
null
,那么使用??
。如果你想丢弃零和空字符串,那么使用||
。老实说,我想不出现在有多少理由需要使用||
,除非你支持旧的环境并且不转译你的代码。但那也是比较小众的情况。 - VLAZnull
或 undefined
的源中分配一个变量,但希望为该变量提供默认值时,使用空值合并运算符 ??
。/* parse the url pattern
/search?keyword=mykeyword&page=3
/search?keyword=mykeyword
*/
ngOnInit(): void {
const keyword = this.route.snapshot.queryParamMap.get('keyword') ?? 'default keyword';
const page = this.route.snapshot.queryParamMap.get('page') ?? '0';
this.queryResult$ = this.service.getQueryResult(keyword, +page);
this.keyword = keyword;
}
[1]:
每种编程语言都有其自己对于假值和真值的定义。判断一个值是否为真值的基本方法是,如果显式类型转换函数 bool(value)
的结果为 true
,那么该值就是真值。
??
。在目前的 JavaScript 中,使用逻辑或运算符||
可以实现类似的功能,但是存在一些问题。当左操作数为 falsy 值时(例如空字符串、0、false 等),逻辑或运算符将返回右操作数。这可能会导致意外的行为,尤其是在比较数字或布尔值时。nullish 合并运算符解决了这个问题,它只有在左侧操作数为 null 或 undefined 时才会返回右侧操作数。否则,它将返回左侧操作数。这使得代码更加可读、明确和健壮。举例来说,考虑以下代码片段:let foo = null ?? 'default'; console.log(foo); // 'default' let bar = 0 || 'default'; console.log(bar); // 'default'
在上面的代码中,foo
的值将是'default'
,而bar
的值将是0
,这可能不是预期的结果。使用 nullish 合并运算符可以避免这种情况,代码如下所示:let foo = null ?? 'default'; console.log(foo); // 'default' let bar = undefined ?? 'default'; console.log(bar); // 'default'
- ASDFGerte0
的婴儿,或者某个测试结果为0
的人 - 值是已知的(因此不是null),但会被视为假。 - mikemaccana??
,否则我会使用||
。 - O-9