简体   繁体   English

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

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

Related to Is there a "null coalescing" operator in JavaScript?JavaScript 中是否存在“空值合并”运算符相关? - JavaScript now has a ?? - JavaScript 现在有一个?? operator which I see is in use more frequently.我看到的运算符使用频率更高。 Previously most JavaScript code used ||以前使用的大多数 JavaScript 代码|| . .

let userAge = null

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

In what circumstances will ??在什么情况下会?? and |||| behave differently?表现不同?

The OR operator || OR 运算符|| uses the right value if left is falsy , while the nullish coalescing operator ??如果 left 是falsy则使用正确的值,而 nullish 合并运算符?? uses the right value if left is null or undefined .如果 left 是nullundefined ,则使用正确的值。

These operators are often used to provide a default value if the first one is missing.如果缺少第一个运算符,这些运算符通常用于提供默认值。

But the OR operator ||但是 OR 运算符|| can be problematic if your left value might contain "" or 0 or false (because these are falsy values ) :如果您的左值可能包含""0false (因为这些是虚假值),则可能会出现问题

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"

In many cases, you might only want the right value if left is null or undefined .在许多情况下,如果 left 是nullundefined ,您可能只需要正确的值。 That's what the nullish coalescing operator ??这就是无效的合并运算符?? is for:适用于:

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"

While the ???? operator isn't available in current LTS versions of Node (v10 and v12), you can use it with some versions of TypeScript or Node:运算符在当前 LTS 版本的 Node (v10 和 v12)中不可用,您可以将其与 TypeScript 或 Node 的某些版本一起使用:

The ?? ?? operator was added to TypeScript 3.7 back in November 2019.运算符于 2019 年 11 月被添加到TypeScript 3.7中。

And more recently, the ??而最近, ?? operator was included in ES2020 , which is supported by Node 14 (released in April 2020).运算符包含在 ES2020中,由 Node 14(2020 年 4 月发布)支持。

When the nullish coalescing operator ??当无效合并运算符?? is supported, I typically use it instead of the OR operator ||受支持,我通常使用它而不是 OR 运算符|| (unless there's a good reason not to). (除非有充分的理由不这样做)。

In short:简而言之:

The Nullish Coalescing Operator distinguishes between nullish ( null , undefined ) and falsey but defined values ( false , 0 , '' etc.). 空值合并运算符区分null undefined )和虚假但已定义的值( false0''等)。 See the graphic below for more information.有关更多信息,请参见下图。

For ||对于|| (logical OR) nullish and falsey values are the same. (逻辑或)无效值和错误值是相同的。


let x, y

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

As seen above, the difference between the operators ??如上所见,运营商之间的区别?? and |||| is that one is checking for nullish values and one is checking for falsey values.一个是检查值,一个是检查虚假值。 However, there are many instances where they behave the same.但是,在许多情况下它们的行为相同。 That is because in JavaScript every nullish value is also falsey (but not every falsey value is nullish ).这是因为在 JavaScript 中,每个nullish值也是falsey (但不是每个falsey值都是nullish )。

I created a simple graphic to illustrate the relationship of nullish and falsey values in JavaScript:我创建了一个简单的图形来说明 JavaScript 中nullishfalse值的关系:

在此处输入图像描述

Using what we learned above we can create a few examples for different behavior:使用我们上面学到的知识,我们可以为不同的行为创建一些示例:

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

Since the new Nullish Coalescing Operator can differentiate between no value and a falsey value, it can be beneficial if you, for example, need to check if there is no String or an empty String.由于新的Nullish Coalescing Operator可以区分无值和虚假值,因此如果您需要检查是否没有字符串或空字符串,它会很有用。 Generally, you probably want to use ??通常,您可能想使用?? instead of ||而不是|| most of the time.大多数时候。

Last and also least here are the two instances where they behave the same:最后也是最不重要的是它们行为相同的两个实例:

let y

y = null || 'default'        // y = 'default'
y = null ?? 'default'        // y = 'default'

y = undefined || 'default'   // y = 'default'
y = undefined ?? 'default'   // y = 'default'

As a very short rule, you could look at it the opposite way:作为一个非常简短的规则,您可以以相反的方式看待它:

  • || (or) returns the first "truthy" value (or the last value if no "truthy" value exists) (或) returns the first "truthy" value (如果不存在“真实”值,则返回最后一个值)
  • ?? (nullish coalescing) returns the first "defined" value (or the last value if no "defined" value exists) (nullish coalescing) returns the first "defined" value (如果不存在“已定义”值,则返回最后一个值)

Example例子

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

As described in the MDN :MDN中所述:

Contrary to the logical OR ( || ) operator, the left operand is returned if it is a falsy value which is not null or undefined .与逻辑 OR ( || ) 运算符相反,如果左操作数不是nullundefined ,则返回左操作数。 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 ).要为另一个变量foo提供一些默认值,如果您认为某些虚假值可用(例如''0 ),您可能会遇到意外行为。 See below for more examples.有关更多示例,请参见下文。

And also in 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.无论第一个操作数的类型如何,如果将其转换为 Boolean 导致 false,则赋值将使用第二个操作数。 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: :)

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

The null(ish) coalescing operator only works with null and undefined . null(ish) 合并运算符适用于nullundefined So, use the null(ish) coalescing operator when you don't want those values but you will otherwise accept other falsy values :因此,当您不想要这些值但您将接受其他虚假值时,请使用 null(ish) 合并运算符

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

The logical OR will skip over any falsy value and give you the other thing.逻辑 OR 将跳过任何虚假值并为您提供其他内容。 The logical OR will skip over any falsy value and give you the other parameter.逻辑 OR 将跳过任何虚假值并为您提供另一个参数。 This does work and is by now idiomatic, however it is not always what you want: 确实有效,并且现在是惯用的,但它并不总是你想要的:

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

Here are few rules for how to determine which one you need.以下是一些关于如何确定您需要哪一个的规则。 The simplest tests:最简单的测试:

  • do you only want to protect against null (and undefined - it's usually the same thing)?您是否只想防止null (和undefined - 通常是同一件事)? Then use ??然后用?? . . If you aren't sure, it's probably a good idea to default to the nullish coalescing operator.如果您不确定,默认使用 nullish 合并运算符可能是个好主意。
  • do you know you also don't want 0 or "" , for example?例如,您知道您也不想要0""吗? Then use ||然后使用|| . .

The second one is where it actually gets trickly.第二个是它实际上变得棘手的地方。 How do you know you need to discard falsy values?你怎么知道你需要丢弃虚假值? Well, the very first snippet shows what happens if you do that: f(0) will discard the zero and thus produce a different result.好吧,第一个片段显示了如果你这样做会发生什么: f(0)将丢弃零,从而产生不同的结果。 This is a somewhat common source of bugs.这是一个比较常见的错误来源。 Since the construct a = b || c由于构造a = b || c a = b || c is common to introduce a fallback value (in this case c ) it might accidentally fall back to it when you didn't mean to. a = b || c通常会引入回退值(在这种情况下c )它可能会在您无意中意外地回退到它。

function updateAge(years) {
  var yearsToAdd = years || 1;
  return this.age + yearsToAdd
}

This works if you want to provide a fallback for calling updateAge() (no argument) but fails if you call updateAge(0) (no update).如果您想为调用updateAge() (无参数)提供回退,则此方法有效,但如果您调用updateAge(0) (无更新)则失败。 Similarly, you could have:同样,您可以:

function sayMyName(greeting) {
  var prefix = greeting || "Hello, my name is ";
  return prefix + this.firstName;
}

Again, this works for sayMyName() (no argument) but fails for sayMyName("") (explicitly no greeting).同样,这适用于sayMyName() (无参数),但对sayMyName("") (明确地没有问候)。

To generalise, if you are providing a fallback value that's different to the falsy value, then you might have a problem.概括地说,如果您提供的后备值与虚假值不同,那么您可能会遇到问题。 However, if your fallback is the falsy value - num || 0但是,如果您的后备虚假值 - num || 0 num || 0 or str || "" num || 0str || "" str || "" then it doesn't really matter. str || ""那么这并不重要。

It's rare (or should be) that you might expect a mixed type (number, or string, or object, etc) and provide a fallback to it: input || fallback很少(或应该)您可能期望混合类型(数字、或字符串、或 object 等)并为其提供后备: input || fallback input || fallback is valid but will reject empty strings and zeroes. input || fallback是有效的,但会拒绝空字符串和零。 It's usually going to be wrong unless you explicitly don't want any of those.除非您明确不想要其中任何一个,否则通常会出错。

To put it simply, you should likely use the nullish coalescing operator ??简而言之,您可能应该使用空值合并运算符?? at all times.每时每刻。 It will be less cognitive load to figure out whether it's a potential bug or not.弄清楚它是否是潜在的错误将减少认知负担。 There is also not much reason to avoid it.也没有太多理由避免它。 It's newer than the boolean OR, so it doesn't work on older environments, that's true, however nowadays you should likely be transpiling your code for those.它比 boolean OR 更新,因此它不适用于旧环境,这是真的,但是现在您可能应该为这些环境编译代码。 If you cannot or prefer not to, then you don't have a choice and should use the boolean OR.如果您不能或不愿意,那么您别无选择,应该使用 boolean OR。

Base on MDN docs :基于MDN 文档

Contrary to the logical OR (||) operator , the left operand is returned if it is a falsy value which is not null or undefined .逻辑 OR (||) 运算符相反,如果左操作数不是nullundefined ,则返回左操作null

Conceptual Example:概念示例:

  • When use ||使用时|| for a falsy value that is NOT undefined or null :对于不是undefinednullnull值:

     false || 'name'; // ==> the 'name' is returned
  • But when using ??但是当使用?? for above case:对于上述情况:

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

Real Example : Assume, we have a phone variable that is not mandatory in our form and the empty string ( '' ) is valid for us and we wanna doSomething() if the phone variable is null or undefined , now guess what:真实示例:假设我们的表单中有一个非强制性的phone变量,并且空字符串 ( '' ) 对我们有效,如果phone变量是nullundefined ,我们想要doSomething() ,现在猜猜看:

  • When use ||使用时|| for a falsy value that is NOT undefined or null :对于不是undefinednullnull值:

     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

Note : actually it is an example and in a real project you can have a better sense of this lovely operation usage.注意:实际上这是一个示例,在实际项目中您可以更好地了解这个可爱的操作用法。

Attention : for the undefined or null both of them act like each other.注意:对于undefinednull两者的行为相同。

When the |||| is being used as a boolean conditional that goes to false.正被用作 boolean 条件变为假。 For example:例如:

let userAge = false

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

The logical OR will still give the next value for anything that doesn't evaluate to true .逻辑 OR 仍然会为任何不评估为true的东西给出下一个值。 So it gives the value 21 in this case.所以在这种情况下它给出的值是21 Where ??哪里?? only handles null and undefined .仅处理nullundefined

In short, when you care that let a variable assigned from a possible null undefined source, and you wish to provide a default value to the variable , use the nullish coalescing operator ??简而言之,当您关心让从可能的null undefined源分配的变量,并且您希望为变量提供默认值时,请使用 nullish 合并运算符?? . .

If you want to avoid messing yourself around with the JavaScript definition of falsy truthy [1], then don't use ||.如果您想避免混淆 JavaScript 的 falsy truthy [1] 定义,请不要使用 ||。

nullish coalescing operator?? 无效的合并运算符??

JavaScript definition of falsy JavaScript falsy的定义

a real example in angular 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]: Each programming language has its own definition of falsy truthy. [1]:每种编程语言都有自己对 falsy truthy 的定义。 The basic approach to tell whether a value is a truthy value is that if the explicit type conversion function bool(value) results in true , then the value is truthy .判断一个值是否为真值的基本方法是,如果显式类型转换function bool(value)结果为true ,则该值是真值。

For those might work across languages, PHP and C# also have ??对于那些可能跨语言工作的,PHP 和 C# 也有?? . . See PHP , C# .PHPC#

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM