【问题标题】:Optional Chaining in JavaScript [duplicate]JavaScript中的可选链接[重复]
【发布时间】:2014-11-28 19:22:02
【问题描述】:

我最近使用 Swift 进行了很多编程。今天,当我遇到问题时,我在 JavaScipt 中做了一些工作:

在 JavaScript 中有没有类似于可选链的东西?没有任何变量来防止undefined is not an object 的方法?

例子:

function test(){
   if(new Date() % 2){
      return {value: function(){/*code*/}};
   }
} 

test().value();

会失败一半,因为有时test 返回未定义。

我能想到的唯一解决方案是函数:

function oc(object, key){
   if(object){
      return object[key]();
   }
}

oc(test(), 'value');

我希望能够做类似的事情:

test()?.value()

问号后面的部分只有在test返回一个对象时才会执行。

但这不是很优雅。有更好的吗?运算符的神奇组合?

编辑我知道我可以重写test 来返回一些东西。但我想知道是否有类似可选链接的东西。我对上述示例的特定解决方案不感兴趣。如果无法控制返回未定义的函数,我也可以使用。

【问题讨论】:

  • test() 返回 undefined 时你希望 value() 返回什么?
  • @ZaheerAhmed 错误或未定义。真的没关系。
  • 可以在未定义的情况下包装现有函数返回一个默认值,无需重写。您还可以在调用时使用三元 (x?y:z)() 或默认运算符 (x||y)()。
  • 我在想你可以对每个你想要默认的包装器使用相同的包装器,即使只是一组函数名和一个 map(),但也许我不明白目标.函数在 JS 中很容易出错,所以它不应该采用重复或样板。 RE:编辑,“(x=test()) && x.value()” 比包装器短,或者如果你有时返回一个真值而不是一个对象, (x=test()) && x.value && x.value();但是对函数进行操作的可重用函数会留下更简洁的代码。
  • 是的,我知道。我只是想知道 JavaScript 中是否有类似可选链接的东西,因为 JS 充满了惊喜。

标签: javascript optional-chaining


【解决方案1】:

可选链已登陆 JS。我们可以通过?. 运算符在对象属性访问中使用可选链接。它允许我们尝试访问可能不存在的对象的属性(即undefined)而不会引发错误。

这是一个代码示例:

const obj = {
  foo: {
    bar: 1
  }
};

// If we try to access property which doesn't exists
// it just returns undefined
console.log(obj.baz);

try {
  // Now we try to access a property of undefined which throws an error
  obj.baz.foz;
} catch (e) {
  console.dir(e.message);
}

// Now we use the optional chaining operator ?.
// We get undefined instead of an error
console.log(obj.baz?.foz);
            
console.log(obj.foo?.bar);

【讨论】:

    【解决方案2】:

    目前这是第 4 阶段提案,您可以在此处查看进度:
    https://github.com/tc39/proposal-optional-chaining

    今天就可以使用 babel 插件了:
    https://www.npmjs.com/package/babel-plugin-transform-optional-chaining

    2020 年 1 月 11 日更新: Babel 现在默认支持可选链 https://babeljs.io/blog/2020/01/11/7.8.0

    可选链接运算符拼写为?.。它可能出现在三个位置:

    obj?.prop       // optional static property access
    obj?.[expr]     // optional dynamic property access
    func?.(...args) // optional function or method call
    

    注意事项:

    为了让foo?.3:0被解析为foo ? .3 : 0(向后兼容的需要),在词法语法级别添加了一个简单的lookahead,这样?.的字符序列就不会被解释在这种情况下作为单个标记(?. 标记不能紧跟十进制数字)。

    也值得一试:

    https://github.com/tc39/proposal-nullish-coalescing

    https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-nullish-coalescing-operator

    【讨论】:

    • 这应该是 2020 年的首选答案。
    【解决方案3】:

    var Obj = {Prop: {name: 'peter'}}

    console.log(Obj.Prop.name) console.log(Obj?.Prop?.name)

    在第一句话中,您只是在访问对象属性。问题在于,如果您发现 Prop 不是对象,它将引发异常。这就是optional chainig operator 的原因。

    假设你尝试做Obj.Prop2.name。 你会得到Uncaught TypeError: Cannot read property 'name' of undefined 如果相反,您执行了Obj.Prop2?.name,您只会收到undefined 作为值,而不是异常。

    这在访问深度嵌套的属性时特别有用。

    警告:这是一个相对较新的 JS 功能,尚未在所有浏览器中实现,因此在将其用于生产应用程序时要小心。

    【讨论】:

      【解决方案4】:

      可选链终于在 JavaScript 标准中了!

      这里有几个例子:

      // properties
      foo?.bar
      foo?.bar()
      foo?.bar.baz()
      foo?.bar?.baz()
      
      // indexing
      foo?.[0]
      foo?.['bar']
      
      // check if a function is defined before invoking
      foo?.()
      foo.bar?.()
      foo?.bar?.()
      

      这比大多数人用来手动检查空值的方法要好得多

      而不是评估

      foo?.bar
      

      对于这个小代码sn-p我们都习惯写

      foo ? foo.bar : null
      

      它实际上计算为

      foo == null ? undefined : foo.bar
      

      适用于所有虚假值,如空字符串、0 或 false。


      与问题无关,但您可能也对?? 运算符感兴趣。

      它的用途与|| 相似,只是它只检查 null 或 undefined。

      例如:

      foo ?? bar
      

      将等同于:

      foo != null ? foo : bar
      

      这是一项非常新的功能,因此即使很多用户已经使用支持此功能的浏览器,您仍然希望使用工具将其转换为旧版本的 javascript。

      【讨论】:

        【解决方案5】:

        你可以使用

        test() && test().value();
        

        var testResult = test();
        testResult && testResult.value();
        

        如果你问我,这与 Swift 的可选链最相似。

        【讨论】:

        • test() && test().value() 是不合适的,如果test 有副作用或者如果test 返回除nullundefined 以外的虚假值,当然如果test() 仍然失败没有value 属性,或者它的value 属性不是函数。
        【解决方案6】:

        在纯 JavaScript 中,您必须进行类型检查或构建代码,以便您知道对象将存在。

        CoffeeScript 是一种编译为 JavaScript 的语言,如果您愿意考虑使用预处理语言,它提供了一个存在运算符 ?. 用于安全链接。

        还有另一个讨论 here 关于为什么你不能在 JS 中重现这种行为。

        还有一个讨论 on the ESDiscuss forums 关于在 JavaScript 的未来版本中添加存在运算符。不过,它似乎并没有走得太远,当然离实际使用还很遥远。在这一点上更多的想法。

        【讨论】:

        • 我接受了你的回答,因为它确实回答了我的问题,不像下面的其他答案,因为它提供了一些有趣的信息。
        【解决方案7】:

        如果 test 是一个对象方法,你总是可以return this;

        但是为什么要通过创建模拟函数来防止此类错误呢?

        【讨论】:

        • OP 提出了一个关于安全链接的一般性问题,而不是如何构建特定功能以确保安全。
        【解决方案8】:

        如果条件不满足,返回一个什么都不做的 noop 函数呢?

        function test(){
           if(new Date() % 2){
              return {value: function(){/*code*/}};
           }
           return {value: function(){ /* just return a type consistent with the function above */ }
        } 
        

        【讨论】:

        • 这只是一个例子。我说的是我无法控制的功能。
        • 明白了。对不起。您需要像 Groovy 中的 ?. 运算符。 JS中没有这样的东西。
        • @sebnukem - 现在有针对该运营商的建议 - 请参阅我的回答
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-22
        • 2021-10-20
        • 2012-06-17
        相关资源
        最近更新 更多