120

JavaScript 中是否存在“空值合并”运算符相关?- JavaScript 现在有一个??运算符,我看到它使用得更频繁。以前大多数 JavaScript 代码使用||.

let userAge = null

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

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

4

7 回答 7

193

||如果 left 是falsy,OR 运算符使用正确的值,而如果 left 是or ,则空值合并运算符??使用正确的值。nullundefined

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

但是,||如果您的左值可能包含""or0false(因为这些是假值 ,则 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"

在许多情况下,如果 left 是null或,您可能只需要正确的值undefined。这就是 nullish 合并运算符??的用途:

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 月发布)支持。

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

于 2020-04-28T13:40:44.223 回答
51

简而言之:

值合并运算符区分值( null, undefined) 和虚假但已定义的值 ( false,0'')。有关更多信息,请参见下图。

对于||(逻辑或)无效值和错误值是相同的。


let x, y

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

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

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

在此处输入图像描述

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

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'
于 2020-09-16T16:12:34.077 回答
22

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

  • ||(或)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)
于 2021-06-04T07:29:22.437 回答
5

MDN中所述:

与逻辑 OR ( ) 运算符相反,如果左操作数是非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! :)
于 2020-04-28T13:16:52.567 回答
5

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) 合并运算符适用于nulland undefined。因此,当您不想要这些值但您将接受其他虚假值时,请使用 null(ish) 合并运算符

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

逻辑 OR 将跳过任何虚假值并为您提供其他内容。逻辑 OR 将跳过任何虚假值并为您提供另一个参数。 确实 有效,并且现在是惯用的,但它并不总是你想要的:

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

以下是一些关于如何确定您需要哪一个的规则。最简单的测试:

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

第二个是它实际上变得棘手的地方。你怎么知道你需要丢弃虚假值?好吧,第一个片段显示了如果你这样做会发生什么: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 || 0或者str || ""它并不重要。

很少(或应该)您可能期望混合类型(数字、字符串或对象等)并为其提供后备:input || fallback有效但会拒绝空字符串和零。除非您明确不想要其中任何一个,否则通常会出错。

简而言之,您应该始终使用 nullish 合并运算符??。弄清楚它是否是潜在的错误将减少认知负担。也没有太多理由避免它。它比布尔 OR 更新,因此它不适用于旧环境,这是真的,但是现在您可能应该为这些环境编译代码。如果您不能或不想这样做,那么您别无选择,应该使用布尔 OR。

于 2020-04-28T13:20:04.770 回答
2

||用作布尔条件时,它会变为假。例如:

let userAge = false

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

逻辑 OR 仍然会为任何不评估为 的东西提供下一个值true。所以它21在这种情况下给出了价值。仅??处理nullundefined.

于 2020-04-28T13:17:00.693 回答
1

基于MDN 文档

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

概念示例:

  • ||用于NOT或 `null的虚假值时: undefined

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

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

真实示例:假设我们phone的表单中有一个不是强制性的变量,并且空字符串 ( '') 对我们有效,我们想doSomething()如果phone变量是nullor undefined,现在猜猜看:

  • ||用于NOT或 `null的虚假值时: undefined

    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两者都表现得像彼此。

于 2020-07-20T15:59:15.980 回答