javascript中是否存在null-coalescing(Elvis)运算符或安全导航运算符?

tia*_*mac 185 javascript jquery groovy safe-navigation-operator

我将通过例子解释:

猫王运营商(?:)

"Elvis运算符"是Java三元运算符的缩写.这方面的一个实例是,如果表达式解析为false或null,则返回"合理的默认值".一个简单的例子可能如下所示:

def gender = user.male ? "male" : "female"  //traditional ternary operator usage

def displayName = user.name ?: "Anonymous"  //more compact Elvis operator
Run Code Online (Sandbox Code Playgroud)

安全导航操作员(?.)

安全导航操作符用于避免NullPointerException.通常,在引用对象时,可能需要在访问对象的方法或属性之前验证它是否为null.为了避免这种情况,安全导航操作符将只返回null而不是抛出异常,如下所示:

def user = User.find( "admin" )           //this might be null if 'admin' does not exist
def streetName = user?.address?.street    //streetName will be null if user or user.address is null - no NPE thrown
Run Code Online (Sandbox Code Playgroud)

Lim*_*ime 127

您可以使用逻辑"OR"运算符代替Elvis运算符:

例如displayname = user.name || "Anonymous".

但Javascript目前没有其他功能.如果你想要一种替代语法,我建议你看一下CoffeeScript.它有一些类似于你正在寻找的速记.

例如存在运算符

zip = lottery.drawWinner?().address?.zipcode
Run Code Online (Sandbox Code Playgroud)

功能快捷方式

()->  // equivalent to function(){}
Run Code Online (Sandbox Code Playgroud)

性感功能呼唤

func 'arg1','arg2' // equivalent to func('arg1','arg2')
Run Code Online (Sandbox Code Playgroud)

还有多行评论和课程.显然你必须将其编译为javascript或插入页面,<script type='text/coffeescript>'但它增加了很多功能:).使用<script type='text/coffeescript'>实际上仅用于开发而非生产.

  • 在大多数情况下,逻辑或不完全是必需的,因为你可能希望它只在左边是未定义的情况下选择正确的操作数,而不是在定义和假的时候. (12认同)
  • 虽然这回答了这个问题,但几乎完全是关于coffeescript而不是javascript,并且超过一半用于描述与OP无关的coffeescript利益.我建议将其归结为与问题相关的内容,就像coffeescript的其他好处一样美妙. (12认同)
  • 我要去香蕉吗?当然,user2451227(目前有4票)的异议是无效的,因为如果表达式/左操作数被定义和假,则三元的中间操作数(即带有Elvis运算符的右操作数)同样不会被选中.在这两种情况下,你都必须去`x === undefined`. (4认同)
  • CoffeeScript 主页使用 `&lt;script type="text/coffeescript"&gt;`。 (2认同)
  • 请考虑更新此内容以提及[可选链接运算符,`?.`,](//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining)。[浏览器支持](//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining#Browser_compatibility) 还没有达到我将其用于一般代码的程度,但它是标题朝那个方向。此外,现在还有[空合并运算符 (??)](//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_Coalescing_Operator#Browser_compatibility),具有类似的状态。 (2认同)

sam*_*son 104

我认为以下相当于安全导航操作符,虽然有点长:

var streetName = user && user.address && user.address.street;
Run Code Online (Sandbox Code Playgroud)

streetName然后将是任一值user.address.streetundefined.

如果您希望它默认为其他东西,您可以与上面的快捷方式结合使用或给出:

var streetName = (user && user.address && user.address.street) || "Unknown Street";
Run Code Online (Sandbox Code Playgroud)

  • 加上一个用于空传播和空合并的好例子! (7认同)
  • 这有效,只是你不知道你是否从中得到 null 或 undefined (3认同)

Fré*_*idi 82

Javascript的逻辑OR运算符短路的,可以替换您的"Elvis"运算符:

var displayName = user.name || "Anonymous";
Run Code Online (Sandbox Code Playgroud)

但是,据我所知,与您的?.运营商无关.

  • +1,我忘记了`||`可以这样使用.请注意,这不仅会在表达式为"null"时合并,而且还会在未定义,"false","0"或空字符串时合并. (13认同)

jab*_*tta 81

2020 更新

JavaScript 现在具有 Elvis Operator 和 Safe Navigation Operator 的等效项。


安全的财产访问

可选的链接运营商?.)是目前阶段4 ECMAScript的建议。你今天可以在 Babel 中使用它

// `undefined` if either `a` or `b` are `null`/`undefined`. `a.b.c` otherwise.
const myVariable = a?.b?.c;
Run Code Online (Sandbox Code Playgroud)

逻辑AND运算符&&)是“老”,更详细的处理这种情况的方式。

const myVariable = a && a.b && a.b.c;
Run Code Online (Sandbox Code Playgroud)

提供默认值

所述nullish合并运算符??)是目前阶段4的ECMAScript提案。你今天可以在 Babel 中使用它。如果运算符的左侧是空值 ( null/ undefined),它允许您设置默认值。

const myVariable = a?.b?.c ?? 'Some other value';

// Evaluates to 'Some other value'
const myVariable2 = null ?? 'Some other value';

// Evaluates to ''
const myVariable3 = '' ?? 'Some other value';
Run Code Online (Sandbox Code Playgroud)

逻辑OR运算符||)是一种替代解决方案略有不同的行为。如果运算符的左侧为falsy ,它允许您设置默认值。请注意,myVariable3下面的结果与myVariable3上面的不同。

const myVariable = a?.b?.c || 'Some other value';

// Evaluates to 'Some other value'
const myVariable2 = null || 'Some other value';

// Evaluates to 'Some other value'
const myVariable3 = '' || 'Some other value';
Run Code Online (Sandbox Code Playgroud)

  • 这个答案需要更多的赞成票。Nullish Coalescing Operator 现在处于第 4 阶段。 (3认同)
  • `a &amp;&amp; ab &amp;&amp; ac` 应该是 `a &amp;&amp; ab &amp;&amp; abc`。我无法自己编辑它,因为这对于 SO 来说还不够大,无法接受,而且我不想做“改变无关紧要的事情以使其达到 6 个字符”的事情。 (2认同)

Jam*_*pic 62

我偶尔会发现以下习语很有用:

a?.b?.c
Run Code Online (Sandbox Code Playgroud)

可以改写为:

((a||{}).b||{}).c
Run Code Online (Sandbox Code Playgroud)

它利用了一个对象上获得未知属性返回undefined,而不是因为它在抛出异常的事实null或者undefined,所以我们导航之前更换null和undefined一个空对象.

  • 好吧,它很难读,但它比那些冗长的`&&`方法更好.+1. (13认同)

ton*_*y_k 23

我认为lodash _.get()可以在这里提供帮助,比如_.get(user, 'name')更复杂的任务_.get(o, 'a[0].b.c', 'default-value')

  • 这个方法的主要问题是,由于属性的名称是字符串,因此您不能再使用具有100%信任的IDE的重构功能 (4认同)

Jac*_*uck 16

还没.也许很快 目前有一个规范草案:

https://github.com/tc39/proposal-optional-chaining

https://tc39.github.io/proposal-optional-chaining/

现在,虽然,我喜欢用lodashget(object, path [,defaultValue])DLVdelve(obj, keypath)

  • 可选链最近刚刚转移到[阶段 4](https://github.com/tc39/agendas/blob/master/2019/12.md),所以我们将在 ES2020 中看到它 (4认同)

hob*_*bbs 12

对于前者,您可以使用||.Javascript"逻辑或"运算符,而不是简单地返回固定的true和false值,如果它为真,则遵循返回其左参数的规则,否则评估并返回其右参数.如果你只对真值感兴趣,那么它的效果会相同,但它也意味着foo || bar || baz返回包含真值的foo,bar或baz中最左边的一个.

但是,您找不到可以将false与null区分开来的,0和空字符串都是false值,因此请避免使用可以合法地为0或0 的value || default构造.value""

  • 很好的工作,注意当左操作数是非null falsey值时,这可能导致意外行为. (4认同)

doc*_*ess 5

这通常称为空合并运算符。Javascript没有。

  • 从严格意义上讲,它为true,但正如其他答案所指出的那样,JavaScript的逻辑OR运算符的行为类似于* false *-算术运算符,使您可以在许多情况下实现同样的简洁。 (3认同)

Jus*_*ier 5

您可以通过以下方式实现大致相同的效果:

var displayName = user.name || "Anonymous";
Run Code Online (Sandbox Code Playgroud)


cdm*_*kay 5

这是等效的简单elvis运算符:

function elvis(object, path) {
    return path ? path.split('.').reduce(function (nestedObject, key) {
        return nestedObject && nestedObject[key];
    }, object) : object;
}

> var o = { a: { b: 2 }, c: 3 };
> elvis(o)

{ a: { b: 2 }, c: 3 }

> elvis(o, 'a');

{ b: 2 }

> elvis(o, 'a.b');

2

> elvis(o, 'x');

undefined
Run Code Online (Sandbox Code Playgroud)


gaz*_*rgo 5

就在这里!

可选链接处于第3阶段,这使您可以使用user?.address?.street公式。

如果您迫不及待想要发布,请安装@babel/plugin-proposal-optional-chaining并使用它。这是适用于我的设置,或者只是阅读Nimmo的文章

// package.json

{
  "name": "optional-chaining-test",
  "version": "1.0.0",
  "main": "index.js",
  "devDependencies": {
    "@babel/plugin-proposal-optional-chaining": "7.2.0",
    "@babel/core": "7.2.0",
    "@babel/preset-env": "^7.5.5"
  }
  ...
}
Run Code Online (Sandbox Code Playgroud)
// .babelrc

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "debug": true
      }
    ]
  ],
  "plugins": [
    "@babel/plugin-proposal-optional-chaining"
  ]
}
Run Code Online (Sandbox Code Playgroud)
// .babelrc

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "debug": true
      }
    ]
  ],
  "plugins": [
    "@babel/plugin-proposal-optional-chaining"
  ]
}
Run Code Online (Sandbox Code Playgroud)

  • 他问是否有一个,是否可以增加一个。考虑到不是要求什么,我认为这不是超级有用。 (3认同)
  • 它已达到ECMAScript标准化流程的第3阶段。es2020-https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining (2认同)

nul*_*ook 5

2019 年 9 月更新

是的,JS 现在支持这个。可选链即将发布到 v8阅读更多