ES6/2015中的Null-safe属性访问(和条件赋值)

时间:2022-05-13 11:50:19

Is there a null-safe property access (null propagation / existence) operator in ES6 (ES2015/JavaScript.next/Harmony) like ?. in CoffeeScript for example? Or is it planned for ES7?

ES6 (ES2015/JavaScript.next/Harmony)中是否有空安全属性访问(null propagation / existence)操作符?例如在CoffeeScript吗?或者它是为ES7计划的?

var aThing = getSomething()
...
aThing = possiblyNull?.thing

This will be roughly like:

大致是这样的:

if (possiblyNull != null) aThing = possiblyNull.thing

Ideally the solution should not assign (even undefined) to aThing if possiblyNull is null

理想情况下,如果可能的话,解决方案不应该赋值(甚至没有定义)。

9 个解决方案

#1


53  

A feature that accomplishes that is currently in stage 1: Optional Chaining.

当前处于第一阶段的特性:可选链接。

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

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

If you want to use it today, there is a Babel plugin that accomplishes that.

如果你现在想要使用它,有一个Babel插件可以实现这一点。

https://github.com/davidyaha/ecmascript-optionals-proposal

https://github.com/davidyaha/ecmascript-optionals-proposal

Update (2017-08-01): If you want to use an official plugin, you can try the alpha build of Babel 7 with the new transform. Your mileage may vary

更新(2017-08-01):如果你想使用一个官方的插件,你可以使用新的转换来尝试Babel 7的alpha构建。你的情况可能不同

https://www.npmjs.com/package/babel-plugin-transform-optional-chaining

https://www.npmjs.com/package/babel-plugin-transform-optional-chaining

#2


26  

No. You may use lodash#get or something like that for this in JavaScript.

不。你可以在JavaScript中使用lodash#get或类似的东西。

#3


25  

It's not as nice as the ?. operator, but to achieve a similar result you could do:

它没有那个好。操作员,但要达到类似的结果,你可以:

user && user.address && user.address.postcode

Since null and undefined are both falsy values (see this reference), the property after the && operator is only accessed if the precedent it not null or undefined.

由于null和undefined都是falsy值(请参阅此引用),所以只有在先例不为null或未定义的情况下才访问&&操作符之后的属性。

Alternatively, you could write a function like this:

或者,您可以编写如下函数:

function _try(func, fallbackValue) {
    try {
        return func();
    } catch (e) {
        return fallbackValue;
    }
}

Usage:

用法:

_try(() => user.address.postcode) // return postcode or undefined 

Or, with a fallback value:

或者,返回值:

_try(() => user.address.postcode, "") // return postcode or empty string

#4


8  

Vanilla alternative for safe property access

香草为安全财产存取的选择

(((a.b || {}).c || {}).d || {}).e

The most concise conditional assignment would probably be this

最简洁的条件分配可能是这样的

try { b = a.b.c.d.e } catch(e) {}

#5


6  

No, there is no null propagation operator in ES6. You will have to go with one of the known patterns.

不,ES6中没有空传播运算符。你必须使用已知的模式之一。

You may be able to use destructuring, though:

不过你也可以使用析构法:

({thing: aThing} = possiblyNull);

There are many discussions (e.g. this) to add such an operator in ES7, but none really took off.

在ES7中添加这样的操作符有很多讨论(例如这个),但没有一个真正成功。

#6


3  

Going by the list here, there is currently no proposal to add safe traversal to Ecmascript. So not only is there no nice way to do this, but it is not going to be added in the forseeable future.

根据这里的列表,目前还没有向Ecmascript添加安全遍历的建议。所以不仅没有很好的方法,而且在可预见的未来也不会增加。

#7


1  

I thought this question needed a bit of a refresh for 2018. This can be done nicely without any libraries using Object.defineProperty() and can be used as follows:

我认为这个问题需要在2018年得到一点启示。无需使用Object.defineProperty()的任何库,就可以很好地完成这项工作,并且可以如下所示:

myVariable.safeGet('propA.propB.propC');

I consider this safe (and js-ethical) because of the writeable and enumerable definitions now available for the defineProperty method of Object, as documented in MDN

我认为这是安全的(和js-ethical的),因为MDN中描述的对象的defineProperty方法现在有可写和可枚举的定义

function definition below:

函数定义如下:

Object.defineProperty(Object.prototype, 'safeGet', { 
    enumerable: false,
    writable: false,
    value: function(p) {
        return p.split('.').reduce((acc, k) => {
            if (acc && k in acc) return acc[k];
            return undefined;
        }, this);
    }
});

I've put together a jsBin with console output to demonstrate this. Note that in the jsBin version I've also added a custom exception for empty values. This is optional, and so I've left it out of the minimal definition above.

我将一个带有控制台输出的jsBin组合在一起来演示这一点。注意,在jsBin版本中,我还为空值添加了一个自定义异常。这是可选的,因此我把它排除在上面的最小定义之外。

Improvements are welcomed

改进的欢迎

#8


0  

I know this is a JavaScript question, but I think Ruby handles this in all of the requested ways, so I think it's a relevant point of reference.

我知道这是一个JavaScript问题,但我认为Ruby以所有被请求的方式处理这个问题,所以我认为这是一个相关的参考点。

.&, try, and && have their strengths and potential pitfalls. A great run down of those options here: http://mitrev.net/ruby/2015/11/13/the-operator-in-ruby/

.&,尝试,&& &有他们的优势和潜在的陷阱。下面是这些选项的一个很好的例子:http://mitrev.net/ruby/2015/11/13/the operator in ruby/

TLDR; The Rubyists conclusion is that dig is both easier on the eyes and a stronger guarantee that a value or null will be assigned.

TLDR;Rubyists的结论是挖掘对眼睛来说更容易而且更强的保证一个值或空值将被赋值。

Here's a simple imeplementation in TypeScript:

在打字稿中有一个简单的imeplementation:

export function dig(target: any, ...keys: Array<string>): any {
  let digged = target
  for (const key of keys) {
    if (typeof digged === 'undefined') {
      return undefined // can also return null or a default value
    }
    if (typeof key === 'function') {
      digged = key(digged)
    } else {
      digged = digged[key]
    }
  }
  return digged
}

This can be used for any depth of nesting and handles functions.

这可以用于任何嵌套深度和处理函数。

a = dig(b, 'c', 'd', 'e');
foo = () => ({});
bar = dig(a, foo, 'b', 'c')

The try approach is equally nice to read in JS, as shown in previous answers. It also does not require looping, which is one drawback of this implementation.

try方法同样适合在JS中阅读,如前面的答案所示。它也不需要循环,这是这个实现的一个缺点。

#9


0  

A safe deep get method seems like a natural fit for underscore.js but there the issue is avoiding string programming. Modifying @Felipe's answer to avoid string programming (or at least pushes edge cases back to the caller):

一个安全的深度获取方法似乎很适合下划线。但是这里的问题是避免字符串编程。修改@Felipe的答案以避免字符串编程(或至少将边缘情况推给调用者):

function safeGet(obj, props) {
   return (props.length==1) ? obj[keys[0]] :safeGet(obj[props[0]], props.slice(1))
}

Example:

例子:

var test = { 
  a: { 
    b: 'b property value',
    c: { }
  } 
}
safeGet(test, ['a', 'b']) 
safeGet(test, "a.b".split('.'))  

#1


53  

A feature that accomplishes that is currently in stage 1: Optional Chaining.

当前处于第一阶段的特性:可选链接。

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

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

If you want to use it today, there is a Babel plugin that accomplishes that.

如果你现在想要使用它,有一个Babel插件可以实现这一点。

https://github.com/davidyaha/ecmascript-optionals-proposal

https://github.com/davidyaha/ecmascript-optionals-proposal

Update (2017-08-01): If you want to use an official plugin, you can try the alpha build of Babel 7 with the new transform. Your mileage may vary

更新(2017-08-01):如果你想使用一个官方的插件,你可以使用新的转换来尝试Babel 7的alpha构建。你的情况可能不同

https://www.npmjs.com/package/babel-plugin-transform-optional-chaining

https://www.npmjs.com/package/babel-plugin-transform-optional-chaining

#2


26  

No. You may use lodash#get or something like that for this in JavaScript.

不。你可以在JavaScript中使用lodash#get或类似的东西。

#3


25  

It's not as nice as the ?. operator, but to achieve a similar result you could do:

它没有那个好。操作员,但要达到类似的结果,你可以:

user && user.address && user.address.postcode

Since null and undefined are both falsy values (see this reference), the property after the && operator is only accessed if the precedent it not null or undefined.

由于null和undefined都是falsy值(请参阅此引用),所以只有在先例不为null或未定义的情况下才访问&&操作符之后的属性。

Alternatively, you could write a function like this:

或者,您可以编写如下函数:

function _try(func, fallbackValue) {
    try {
        return func();
    } catch (e) {
        return fallbackValue;
    }
}

Usage:

用法:

_try(() => user.address.postcode) // return postcode or undefined 

Or, with a fallback value:

或者,返回值:

_try(() => user.address.postcode, "") // return postcode or empty string

#4


8  

Vanilla alternative for safe property access

香草为安全财产存取的选择

(((a.b || {}).c || {}).d || {}).e

The most concise conditional assignment would probably be this

最简洁的条件分配可能是这样的

try { b = a.b.c.d.e } catch(e) {}

#5


6  

No, there is no null propagation operator in ES6. You will have to go with one of the known patterns.

不,ES6中没有空传播运算符。你必须使用已知的模式之一。

You may be able to use destructuring, though:

不过你也可以使用析构法:

({thing: aThing} = possiblyNull);

There are many discussions (e.g. this) to add such an operator in ES7, but none really took off.

在ES7中添加这样的操作符有很多讨论(例如这个),但没有一个真正成功。

#6


3  

Going by the list here, there is currently no proposal to add safe traversal to Ecmascript. So not only is there no nice way to do this, but it is not going to be added in the forseeable future.

根据这里的列表,目前还没有向Ecmascript添加安全遍历的建议。所以不仅没有很好的方法,而且在可预见的未来也不会增加。

#7


1  

I thought this question needed a bit of a refresh for 2018. This can be done nicely without any libraries using Object.defineProperty() and can be used as follows:

我认为这个问题需要在2018年得到一点启示。无需使用Object.defineProperty()的任何库,就可以很好地完成这项工作,并且可以如下所示:

myVariable.safeGet('propA.propB.propC');

I consider this safe (and js-ethical) because of the writeable and enumerable definitions now available for the defineProperty method of Object, as documented in MDN

我认为这是安全的(和js-ethical的),因为MDN中描述的对象的defineProperty方法现在有可写和可枚举的定义

function definition below:

函数定义如下:

Object.defineProperty(Object.prototype, 'safeGet', { 
    enumerable: false,
    writable: false,
    value: function(p) {
        return p.split('.').reduce((acc, k) => {
            if (acc && k in acc) return acc[k];
            return undefined;
        }, this);
    }
});

I've put together a jsBin with console output to demonstrate this. Note that in the jsBin version I've also added a custom exception for empty values. This is optional, and so I've left it out of the minimal definition above.

我将一个带有控制台输出的jsBin组合在一起来演示这一点。注意,在jsBin版本中,我还为空值添加了一个自定义异常。这是可选的,因此我把它排除在上面的最小定义之外。

Improvements are welcomed

改进的欢迎

#8


0  

I know this is a JavaScript question, but I think Ruby handles this in all of the requested ways, so I think it's a relevant point of reference.

我知道这是一个JavaScript问题,但我认为Ruby以所有被请求的方式处理这个问题,所以我认为这是一个相关的参考点。

.&, try, and && have their strengths and potential pitfalls. A great run down of those options here: http://mitrev.net/ruby/2015/11/13/the-operator-in-ruby/

.&,尝试,&& &有他们的优势和潜在的陷阱。下面是这些选项的一个很好的例子:http://mitrev.net/ruby/2015/11/13/the operator in ruby/

TLDR; The Rubyists conclusion is that dig is both easier on the eyes and a stronger guarantee that a value or null will be assigned.

TLDR;Rubyists的结论是挖掘对眼睛来说更容易而且更强的保证一个值或空值将被赋值。

Here's a simple imeplementation in TypeScript:

在打字稿中有一个简单的imeplementation:

export function dig(target: any, ...keys: Array<string>): any {
  let digged = target
  for (const key of keys) {
    if (typeof digged === 'undefined') {
      return undefined // can also return null or a default value
    }
    if (typeof key === 'function') {
      digged = key(digged)
    } else {
      digged = digged[key]
    }
  }
  return digged
}

This can be used for any depth of nesting and handles functions.

这可以用于任何嵌套深度和处理函数。

a = dig(b, 'c', 'd', 'e');
foo = () => ({});
bar = dig(a, foo, 'b', 'c')

The try approach is equally nice to read in JS, as shown in previous answers. It also does not require looping, which is one drawback of this implementation.

try方法同样适合在JS中阅读,如前面的答案所示。它也不需要循环,这是这个实现的一个缺点。

#9


0  

A safe deep get method seems like a natural fit for underscore.js but there the issue is avoiding string programming. Modifying @Felipe's answer to avoid string programming (or at least pushes edge cases back to the caller):

一个安全的深度获取方法似乎很适合下划线。但是这里的问题是避免字符串编程。修改@Felipe的答案以避免字符串编程(或至少将边缘情况推给调用者):

function safeGet(obj, props) {
   return (props.length==1) ? obj[keys[0]] :safeGet(obj[props[0]], props.slice(1))
}

Example:

例子:

var test = { 
  a: { 
    b: 'b property value',
    c: { }
  } 
}
safeGet(test, ['a', 'b']) 
safeGet(test, "a.b".split('.'))