简介
当在一个_请求-响应生命周期_中工作时,你要确保一个带有所需主体的响应--或者至少是一个信息性的响应到达,这样请求数据的客户端就能保持在循环中。在空值的情况下,你可能想返回一个不同的结果。
JavaScript通过其nullish操作符(也称为空值凝聚操作符)确保了这一点,该操作符是在_ECMAScript 2020_中添加到语言中的。有了它,你既可以返回一个值_,也可以_根据布尔表达式将其分配给其他的值。
这可以用来在另一个值缺失的情况下返回默认值,_或者_根据任何其他布尔表达式返回不同的值。
空值凝聚运算符属于短路逻辑运算符组,我们稍后会看一下。
它与条件运算符有些类似,后者有时也被称为三元运算符。
// Null Coalescing Operator //
// If the left-hand side is null, the righthand side is returned
result = nullValue ?? defaultValue
// Conditional operator //
// If the condition is true, the left side is assigned, otherwise, the right side is assigned
condition ? value : value2
在本指南中,我们将通过实际的例子来看看nullish/Null凝聚运算符、短路和真值与假值。
什么是 "短路"?
JavaScript从左到右评估运算符。对于排他性运算符,我们需要两个值都评估为真,有时只检查第一个评估语句就足够了。
如果运算符的左边是false ,不管右边是什么,运算符的结果都是false ,所以评估另一边就没有意义了,为了节省计算能力,会跳过这一边。
这个过程被称为 "短路"。
在ES2020之前,JavaScript只有两个短路的逻辑运算符。
- 逻辑运算符_AND_-
&& - 逻辑运算符_OR_-
||
在新的更新中,JavaScript又引入了一个。
- _空值凝聚_运算符 -
??
短路本身使代码更有效率,因为需要进行更少的评估,不过,通过Null Coalescing操作符,我们也可以根据短路操作来改变代码逻辑。
比如说。
let x = 10;
let y = 20;
let result;
if(x+y > 20){
result = "x+y is greater than 20";
}
console.log(result);
这段代码将导致。
x+y is greater than 20
虽然,我们也可以完全抛弃if 语句,而使用短路和运算符来缩短语句。
let x = 10;
let y = 20;
(x+y) > 20 && console.log("x+y is greater than 20");
(x+y) > 20 评估为true ,因此进入下一个块,并打印出信息。
这里哪里短路了?
如果(x+y) > 20 是_虚假_的(我们将在第二部分谈论这个问题),JavaScript解释器甚至不会去看表达式的第二部分,这个块就永远不会运行。
同样的,我们也可以用类似的方式来使用逻辑OR操作符。
let x = 10;
let y = 20;
(x-y) > 0 || console.log("x+y is lesser than 0");
自然,这样做的结果是。
x+y is lesser than 0
这些例子都很简单,然而逻辑运算符可以解决很多实际问题,并使你的代码更加简洁。然而,如果使用不当,你可能会让自己感到头痛。
真值和假值
在使用逻辑运算符时,你会遇到_真值_和_假值_这两个术语。
真值是指任何不属于以下情况的值。
nullundefined0''- 空字符串falseNaN- 不是一个数字
所有这些值都被认为是假的。
在JavaScript中,当用于循环或if 语句时,所有的_假值_都被评估为false ,所有的_真值_都被评估为true 。
现在我们已经掌握了先决条件,最后让我们来看看Nullish操作符。
归零运算符
Nullish运算符检查值是否为nullish,而不是falsy。一个偏空的值是undefined 或null 。
这允许我们在不确定结果的时候给变量分配默认的非空值。
例如,让我们模拟一个用户服务,从数据库中检索一个用户并返回其姓名。有10%的几率该用户不存在,这可以通过调用Math.random() 来调节。在对数据库的10次调用中,我们可能会看到至少一个失踪的用户--用一个null 的结果表示。
class DbConnection {
find(id) {
if(Math.random() > 0.9) {
return null;
} else {
return `John Doe ${id}`;
}
}
}
const db = new DbConnection();
for (let i = 0; i < 10; i++) {
let user = db.find(i);
if(user != null){
console.log(user);
} else {
console.log('User not found');
}
}
这段代码将输出用户的名字或一条信息,表示该用户在数据库中不存在,尽管这需要我们在if 语句中进行空检查。
这样的结果是。
John Doe 0
John Doe 1
User not found
John Doe 3
John Doe 4
John Doe 5
User not found
User not found
John Doe 8
John Doe 9
Happenchance在这次运行中似乎很奇怪--3个null 的结果!这段代码工作得很好,如果数据库返回一个null 的值,就可以处理null 的情况。
另外,我们还可以使用更简洁的方法。
class DbConnection {
find(id) {
return Math.random() > 0.9 ? null : `John Doe ${id}`
}
}
const db = new DbConnection();
for (let i = 0; i < 10; i++) {
let user = db.find(i) ?? "User not found"
console.log(user)
}
使用一个_条件运算符_,我们返回null 或John Doe 以及它们各自的ID。如果Math.random() > 0.9 ,则返回null ,所以每次调用数据库时有10%的概率会返回。
然后,假设可能的null 值 - 我们使用Nullish 操作符给user 结果分配一个新的值,如果它变成了null 。如果db.find() ,返回null ,右边的值就会被返回。
这段代码比if-else 语句要干净和简短得多,而if-else 语句更容易级联,变得更加复杂。虽然,将多个短路运算符串联起来也会变得难以阅读,所以并不建议替换_所有的_ if-else 块。
let s1 = (Math.random() > 0.5 ? 1 : null) ?? (Math.random() > 0.5 ? 4 : (Math.random() > 0.5 ? null : 1))
console.log(s1)
你知道这将打印出什么吗?考虑到随机的可能性,你可能需要花点时间来手动解析这个,看看你能预见到哪些值。这段代码在某些情况下有导致1 与null 和4 的倾向,因为在这种情况下nullish运算符返回的默认值是_另一个null_。一般来说,在这样的情况下,你不会使用超过一个或两个运算符。
结论
总结一下,_nullish运算符_的唯一目的是允许你总是返回某种默认值,而不是返回不存在的东西--在JavaScript中,这就是null 和undefined 的意思。