Null-safe property access (and conditional assignment) in ES6/2015

岁酱吖の 提交于 2019-12-17 00:01:04

问题


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?

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


回答1:


Update (2019-06-27): Seems people are still finding this, here's the current story:

  • Optional Chaining specification (Stage 2): https://github.com/tc39/proposal-optional-chaining
  • Babel v7 Plugin: https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining

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

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

Original:

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

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

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

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




回答2:


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.

Alternatively, you could write a function like this:

function _try(func, fallbackValue) {
    try {
        var value = func();
        return (value === null || value === undefined) ? fallbackValue : value;
    } catch (e) {
        return fallbackValue;
    }
}

Usage:

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

Or, with a fallback value:

_try(() => user.address.postcode, "none") // return postcode or a custom string



回答3:


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




回答4:


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:


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

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.




回答6:


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.




回答7:


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

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('.'))  



回答8:


// Typescript
static nullsafe<T, R>(instance: T, func: (T) => R): R {
    return func(instance)
}

// Javascript
function nullsafe(instance, func) {
    return func(instance);
};

// use like this
const instance = getSomething();
let thing = nullsafe(instance, t => t.thing0.thing1.thingx);



回答9:


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.

.&, 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/

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.

Here's a simple imeplementation in TypeScript:

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.




回答10:


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:

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

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.

Improvements are welcomed



来源:https://stackoverflow.com/questions/32139078/null-safe-property-access-and-conditional-assignment-in-es6-2015

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!