javascript 空条件运算符

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31610869/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 14:03:43  来源:igfitidea点击:

Null Conditional Operators

javascript

提问by Ian

C# 6.0 has just been released and has a new nice little feature that I'd really like to use in JavaScript. They're called Null-conditional operators. These use a ?.or ?[]syntax.

C# 6.0 刚刚发布,它有一个新的不错的小功能,我真的很想在 JavaScript 中使用它。它们被称为空条件运算符。这些使用?.or?[]语法。

What these do is essentially allow you to check that the object you've got isn't null, before trying to access a property. If the object is null, then you'll get nullas the result of your property access instead.

这些所做的基本上是允许您null在尝试访问属性之前检查您拥有的对象是否不是。如果对象是null,那么您将获得null属性访问的结果。

int? length = customers?.Length;

So here intcan be null, and will take that value if customersis null. What is even better is that you can chain these:

所以这里int可以为空,如果customers为空则取该值。更好的是你可以链接这些:

int? length = customers?.orders?.Length;

I don't believe we can do this in JavaScript, but I'm wondering what's the neatest way of doing something similar. Generally I find chaining ifblocks difficult to read:

我不相信我们可以在 JavaScript 中做到这一点,但我想知道做类似事情的最简洁的方法是什么。一般来说,我发现链接if块难以阅读:

var length = null;
if(customers && customers.orders) {
    length = customers.orders.length;
}

采纳答案by Brent L

Called "optional chaining", it's currently a TC39 proposal in Stage 4. A Babel pluginhowever is already available in v7.

称为“可选链”,目前是第 4 阶段TC39 提案。一通天插件不过是在第7版已经上市。

Example usage:

用法示例:

const obj = {
  foo: {
    bar: {
      baz: 42,
    },
  },
};

const baz = obj?.foo?.bar?.baz; // 42

const safe = obj?.qux?.baz; // undefined

回答by Vladislav

Js logical operators return not trueor false, but trulyor falsyvalue itself. For example in expression x && y, if xis falsy, then it will be returned, otherwise ywill be returned. So the truth table for operator is correct.

Js 逻辑运算符返回 not trueor false, but trulyorfalsy值本身。例如在 expression 中x && y,如果x为假,则将其返回,否则y将返回。所以算子的真值表是正确的。

In your case you could use expression customers && customers.orders && customers.orders.Lengthto get lengthvalue or the first falsyone.

在您的情况下,您可以使用表达式customers && customers.orders && customers.orders.Length来获取length值或第falsy一个值。

Also you can do some magic like ((customers || {}).orders || {}).length(Personally, I don't like this syntax and possible garbage collection pressure as well)

你也可以做一些魔法((customers || {}).orders || {}).length(就个人而言,我不喜欢这种语法和可能的垃圾收集压力)

Or even use maybemonad.

或者甚至使用maybemonad。

function Option(value) {
    this.value = value;
    this.hasValue = !!value;
}

Option.prototype.map = function(s) {
    return this.hasValue
        ? new Option(this.value[s])
        : this;
}

Option.prototype.valueOrNull = function() {
    return this.hasValue ? this.value : null;
}

var length = 
    new Option(customers)
        .map("orders")
        .map("length")
        .valueOrNull();

It's longer than all the previous approaches, but clearly shows your intentions without any magic behind.

它比之前所有的方法都长,但清楚地表明了你的意图,没有任何魔法。

回答by Mariano Desanze

There are several ways to improve code readability (depending on your needs):

有几种方法可以提高代码可读性(取决于您的需求):

  1. You already use babeljs(v7 or above) and you use "Optional Chaining" babel plugin(finished proposal) (or just preset-stage-3):

    const length = customers?.orders?.Length;
    
    // With default value (otherwise it will be `undefined`):
    const length = customers?.orders?.Length || defaultLength;
    
    // File: .babelrc
    { "plugins": ["@babel/plugin-proposal-optional-chaining"] }
    
  2. You already use lodash(v3.7 or greater): Use the lodash.getmethod:

    var length = _.get(customers, 'orders.length');
    
    // With default value (otherwise it will be `undefined`):
    var length = _.get(customers, 'orders.length', defaultLength);
    
  3. Plain javascript:

    var length = customers && customers.orders && customers.orders.length;
    
    // With default value (otherwise it may be whatever falsy value "customers" or "customers.orders" might have):
    var length = (customers
        && customers.orders
        && customers.orders.length) || defaultLength;
    
  1. 您已经使用了babeljs(v7 或更高版本)并且您使用了“可选链接”babel 插件(已完成的提案)(或只是preset-stage-3):

    const length = customers?.orders?.Length;
    
    // With default value (otherwise it will be `undefined`):
    const length = customers?.orders?.Length || defaultLength;
    
    // File: .babelrc
    { "plugins": ["@babel/plugin-proposal-optional-chaining"] }
    
  2. 您已经在使用lodash(v3.7 或更高版本):使用lodash.get方法:

    var length = _.get(customers, 'orders.length');
    
    // With default value (otherwise it will be `undefined`):
    var length = _.get(customers, 'orders.length', defaultLength);
    
  3. 普通的javascript:

    var length = customers && customers.orders && customers.orders.length;
    
    // With default value (otherwise it may be whatever falsy value "customers" or "customers.orders" might have):
    var length = (customers
        && customers.orders
        && customers.orders.length) || defaultLength;
    

回答by J Bryan Price

Here's a quick and dirty version that works.

这是一个有效的快速而肮脏的版本。

String.prototype.nullSafe = function() {
    return eval('var x='+this.replace(/\?/g,';if(x)x=x')+';x');
};

Example usage:

用法示例:

var obj = { 
    Jim: 1,
    Bob: { "1": "B", "2": "o", "3": "b" },
    Joe: [ 1, 2, 3, { a: 20 } ]
};

 obj.Joe[3].a                 // 20    
"obj.Joe[3]?.a".nullSafe()    // 20

 obj.Joe[4].a                 // Error: Can't read 'a' from undefined
"obj.Joe[4].a".nullSafe()     // Error: Can't read 'a' from undefined
"obj.Joe[4]?.a".nullSafe()    // undefined

 obj.Hyman[3].a.b              // Error: Can't read '3' from undefined
"obj.Hyman[3].a.b".nullSafe()  // Error: Can't read '3' from undefined
"obj.Hyman?[3].a.b".nullSafe() // undefined