我应该什么时候使用?? (无效合并)与 || (逻辑或)?

When should I use ?? (nullish coalescing) vs || (logical OR)?

Is there a "null coalescing" operator in JavaScript? 相关 - JavaScript 现在有一个 ?? 运算符,我发现它使用得更频繁。以前大多数 JavaScript 代码使用 ||.

let userAge = null

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

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

MDN所述:

Contrary to the logical OR (||) operator, the left operand is returned if it is a falsy value which is not null or undefined. In other words, if you use || to provide some default value to another variable foo, you may encounter unexpected behaviors if you consider some falsy values as usable (eg. '' or 0). See below for more examples.

还有 the answer to the question you linked:

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! :)

|| 被用作变为 false 的布尔条件时。例如:

let userAge = false

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

逻辑 OR 仍然会为计算结果不为 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));

null(ish) 合并运算符 适用于 nullundefined。因此,当您不想要这些值时使用 null(ish) 合并运算符,否则您将接受其他虚假值:

console.log(null      ?? "nullish");
console.log(undefined ?? "nullish");
console.log(""        ?? "nullish");
console.log(0         ?? "nullish");
console.log(false     ?? "nullish");

逻辑或将跳过任何虚假值并为您提供另一个值。 逻辑或将跳过任何虚假值并为您提供另一个参数。 This does work 现在是惯用的,但它并不总是你想要的:

console.log(null      || "falsy");
console.log(undefined || "falsy");
console.log(""        || "falsy");
console.log(0         || "falsy");
console.log(false     || "falsy");

这里有一些关于如何确定您需要哪一个的规则。最简单的测试:

  • 您是否只想防范 null(和 undefined - 通常是同一件事)?然后使用??。如果您不确定,默认使用无效合并运算符可能是个好主意。
  • 知道你也不想要 0"" 吗?然后使用 ||

第二个是它真正变得棘手的地方。您如何知道您需要丢弃虚假值?好吧,第一个片段显示了如果您这样做会发生什么:f(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。

OR 运算符 || 在 left 为 falsy 时使用右值,而空值合并运算符 ?? 在 left 为 null 或 [ 时使用右值=15=].

这些运算符通常用于在缺少第一个运算符时提供默认值。

但是如果您的左值可能包含 ""0false(因为这些是 falsy values):

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"

虽然 ?? 运算符在 current LTS versions of Node(v10 和 v12)中不可用,但您可以将其与某些版本的 TypeScript 或 Node 一起使用:

?? 运算符已于 2019 年 11 月添加到 TypeScript 3.7

最近,?? 运算符是 included in ES2020,它受 Node 14(2020 年 4 月发布)的支持。

当支持无效合并运算符 ?? 时,我通常使用它来代替 OR 运算符 ||(除非有充分的理由不这样做)。

基于MDN docs

Contrary to the logical OR (||) operator, the left operand is returned if it is a falsy value which is not null or undefined.

概念示例:

  • || 用于 falsy 值时 NOT undefined 或`空:

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

    false ?? 'name'; // ==> the false is returned
    
    

实例: 假设,我们有一个 phone 变量,它在我们的表单中不是必需的,空字符串 ('') 对我们有效,如果 phone 变量是nullundefined,猜猜是什么:

  • || 用于 falsy 值时 NOT undefinednull:

    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 Coalescing Operator区分nullish(null,undefined)和falsey但是定义 值(false0'' 等)。有关详细信息,请参见下图。

对于 ||(逻辑或)空值和假值相同。


let x, y

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

如上所示,运算符 ??|| 之间的区别在于,一个是检查 nullish 值,一个是检查 值。但是,在许多情况下它们的行为相同。这是因为在 JavaScript 中每个 nullish 值也是 falsey(但不是每个 falsey值为 nullish).

我创建了一个简单的图形来说明 nullishfalsey 值在 JavaScript:[=26= 中的关系]

利用我们在上面学到的知识,我们可以为不同的行为创建一些示例:

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 = ''

由于新的 Nullish Coalescing Operator 可以区分无值和假值,如果您需要检查是否没有字符串或空字符串,它会很有用。通常,大多数时候您可能希望使用 ?? 而不是 ||

这里最后也是最不重要的是它们行为相同的两个实例:

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(如果不存在“真实”值,则为最后一个值)
  • ??(无效合并)returns the first "defined" value(如果不存在“已定义”值,则为最后一个值)

示例

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

简而言之,当您关心从可能的 null undefined 来源分配变量,并且您希望为变量提供 默认值时 , 使用无效合并运算符 ??.

如果您想避免弄乱 JavaScript 伪真 [1] 的定义,请不要使用 ||。

nullish coalescing operator ??

JavaScript definition of falsy

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

[1]: 每种编程语言都有自己对 falsy truthy 的定义。判断一个值是否为真值的基本方法是,如果显式类型转换函数 bool(value) 结果为 true,则该值是 truthy.

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