什么时候用??(空合并)vs ||(逻辑OR)?

是否存在“无效合并”;JavaScript中的操作符?相关- JavaScript现在有一个??操作符,我看到它使用得更频繁。以前大多数JavaScript代码使用||

let userAge = null


// These values will be the same.
let age1 = userAge || 21
let age2 = userAge ?? 21

在什么情况下??||会表现不同?

61027 次浏览

中数中所述:

与逻辑OR (||)运算符相反,如果左操作数是一个非nullundefined的假值,则返回该操作数。换句话说,如果你使用||为另一个变量foo提供一些默认值,如果你认为一些错误的值是可用的,你可能会遇到意想不到的行为(例如。''0)。请参见下面的更多示例。

还有在你链接的问题的答案中:

无论第一个操作数的类型是什么,如果将其强制转换为布尔型结果为false,则赋值操作将使用第二个操作数。注意以下所有情况:

alert(Boolean(null)); // false
alert(Boolean(undefined)); // false
alert(Boolean(0)); // false
alert(Boolean("")); // false
alert(Boolean("false")); // true -- gotcha! :)

||被用作布尔条件时,该值为false。例如:

let userAge = false


// These values will be the same.
let age1 = userAge || 21 // 21
let age2 = userAge ?? 21 // false

逻辑“或”仍然会为任何未计算为true的值提供下一个值。所以在本例中,它给出的值是21。其中??只处理nullundefined

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));

空(ish)合并运算符适用于__ABC0和undefined。因此,当您不想要这些值,但您将接受其他假值时,请使用null(ish)合并运算符:

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 -通常是一样的)吗?然后使用??。如果您不确定,那么默认使用空合并操作符可能是个好主意。
  • 例如,你是否也不想要0"" ?然后使用||

第二个问题实际上很棘手。你如何知道你需要丢弃虚假值?好吧,第一个代码片段显示了如果你这样做会发生什么:f(0)将丢弃0,从而产生不同的结果。这是一种常见的错误来源。由于构造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 || 0str || "",那么这并不重要。

很少(或应该是)你可能期望一个混合类型(数字、字符串或对象等),并提供一个回退给它:input || fallback是有效的,但将拒绝空字符串和零。它通常是错误的,除非你明确地不想要这些。

简单地说,你应该一直使用空合并运算符??。判断它是否是一个潜在的错误将会减少认知负担。也没有太多理由去避免它。它比布尔OR更新,所以它不能在旧的环境中工作,这是真的,但是现在你应该为那些环境编译你的代码。如果你不能或不喜欢,那么你没有选择,应该使用布尔or。

如果左为falsy,则OR运算符||使用右值,而如果左为nullundefined,则空合并运算符??使用右值。

如果缺少第一个操作符,这些操作符通常用于提供默认值。

但是,如果你的左值可能包含__ABC1或__ABC2或__ABC3(因为这些是假值),则OR运算符||可能会有问题。:

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"

在许多情况下,如果左边是nullundefined,你可能只想要右边的值。这就是空合并运算符??的用途:

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"

虽然??操作符在Node的当前LTS版本 (v10和v12)中不可用,但你可以在某些版本的TypeScript或Node中使用它:

??操作符是在2019年11月添加到打字稿3.7的。

最近,??操作符是列入ES2020,由Node 14支持(于2020年4月发布)。

当支持空合并运算符??时,我通常使用它而不是OR运算符||(除非有很好的理由不这样做)。

基于MDN文档:

逻辑OR(||)运算符相反,如果左操作数是 nullundefinedfalsy值,则返回该操作数。

概念的例子:

  • 当将||用于 undefinednullfalsy值时:

    false || 'name'; // ==> the 'name' is returned
    
  • 但是当对上述情况使用??时:

    false ?? 'name'; // ==> the false is returned
    
    
    
< p > 真实的例子: 假设,我们有一个phone变量,它在我们的表单中不是强制的,空字符串('')对我们有效,如果phone变量是nullundefined,我们想要doSomething(),现在猜猜看:

  • 当将||用于 undefinednullfalsy值时:

    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
    
  • 但是当对上述情况使用??时:

    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
    

请注意:实际上这是一个例子,在一个真实的项目中,你可以更好地理解这个可爱的操作用法。

注意:对于undefinednull,它们都相互作用。

简而言之

空合并运算符 ??区分:

  • nullish值(nullundefined)
  • Falsey但是有定义值(false0''等)

||(逻辑或)处理这两个相同。

我创建了一个简单的图形来说明JavaScript中nullish美甲师值的关系:

enter image description here

进一步的解释:

let x, y


x = 0
y = x || 'default'            // y = 'default'
y = x ?? 'default'            // y = 0

如上所述,操作符??||之间的区别是,一个检查nullish值,一个检查美甲师值。然而,在许多情况下,它们的行为是相同的。这是因为在JavaScript中,每个nullish值也是美甲师(但不是每个美甲师值都是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'

作为一个非常简短的规则,你可以用相反的方式来看待它:

  • ||(或)returns the first "truthy" value(或最后一个值,如果没有&;truthy"值存在)
  • ??(空合并)returns the first "defined" value(或最后一个值,如果没有"defined"值存在)

例子

x = false || true; // -->  true   (the first 'truthy' value - parameter 2)
x = false ?? true; // -->  false  (the first 'defined' value - parameter 1)

简而言之,当你关心让一个变量从可能的null undefined源赋值,并且你希望提供变量的默认值时,使用空合并运算符??

如果您想避免被伪真理[1]的JavaScript定义搞得一团糟,那么就不要使用||。

null合并运算符??< / >

JavaScript定义的假的

angular的一个真实例子

/* 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;
}
< p > [1]: 每种编程语言都有自己对伪真理的定义。判断一个值是否为真值的基本方法是,如果显式类型转换函数bool(value)的结果为true,则该值为真相.

对于那些可能跨语言工作的,PHP和c#也有??。参见PHPc#