Доступ к нулевым свойствам (и условное назначение) в ES6/2015

Существует ли в SO6 (ES2015/JavaScript.next/Harmony) доступ к свойству (t20 > -safe) доступа к свойствам (нулевое распространение/существование), например ?. в CoffeeScript например? Или это запланировано для ES7?

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

Это будет примерно так:

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

В идеале решение не должно присваивать (даже undefined) значение aThing, если possiblyNull равно null

Ответ 1

Обновление (2019-06-27): кажется, что люди все еще находят это, вот текущая история:

Обновление (2017-08-01): Если вы хотите использовать официальный плагин, вы можете попробовать альфа-сборку Babel 7 с новым преобразованием. Ваш пробег может отличаться

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

Оригинал:

Достигается функция, которая в настоящее время находится на этапе 1: необязательная цепочка.

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

Если вы хотите использовать его сегодня, есть плагин Babel, который выполняет это.

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

Ответ 2

Это не так хорошо, как? оператор, но для достижения аналогичного результата вы могли бы сделать:

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

Поскольку null и undefined являются ложными значениями (см. Эту ссылку), свойство после оператора && доступно только в том случае, если в прецеденте оно не равно null или undefined.

В качестве альтернативы вы можете написать такую функцию:

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

Использование:

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

Или с запасным значением:

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

Ответ 3

Нет. Вы можете использовать lodash # get или что-то в этом роде для JavaScript.

Ответ 4

Альтернатива Vanilla для безопасного доступа к ресурсам

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

Наиболее сжатым условным назначением, вероятно, будет это

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

Ответ 5

Нет, в ES6 нет оператора распространения пустоты. Вам нужно будет пойти с одним из известных шаблонов.

Возможно, вы можете использовать деструктурирование:

({thing: aThing} = possiblyNull);

Существует много дискуссий (например, this), чтобы добавить такой оператор в ES7, но никто не снял.

Ответ 6

Переходя по списку здесь, в настоящее время нет предложения по добавлению безопасного обхода в Ecmascript. Таким образом, не только нет хорошего способа сделать это, но он не будет добавлен в обозримом будущем.

Ответ 7

Безопасный метод глубокого получения выглядит как естественная подгонка для underscore.js, но здесь проблема состоит в том, чтобы избегать строкового программирования. Модифицируйте ответ @Felipe, чтобы избежать программирования строки (или, по крайней мере, отодвинуть крайние случаи назад к вызывающей стороне):

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

Пример:

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

Ответ 8

Я знаю, что это вопрос JavaScript, но я думаю, что Ruby справляется с этим всеми запрошенными способами, поэтому я считаю его уместным ориентиром.

.&, try, и && имеют свои сильные стороны и потенциальные подводные камни. Здесь вы найдете множество вариантов: http://mitrev.net/ruby/2015/11/13/the-operator-in-ruby/

TL;DR; Вывод Rubyists заключается в том, что dig легче для глаз и более надежная гарантия присвоения значения или null.

Вот простая реализация в 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
}

Это может быть использовано для любой глубины вложенности и функций функций.

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

Подход try одинаково хорош для чтения в JS, как показано в предыдущих ответах. Это также не требует зацикливания, что является одним из недостатков этой реализации.

Ответ 9

Я думал, что этот вопрос нуждается в небольшом обновлении для 2018. Это можно сделать без каких-либо библиотек, использующих Object.defineProperty() и его можно использовать следующим образом:

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

Я считаю это безопасным (и js-этическим) из-за доступных для writeable и enumerable определений, теперь доступных для метода defineProperty Object, как документировано в MDN

определение функции ниже:

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);
    }
});

Я собрал jsBin с консольным выводом, чтобы продемонстрировать это. Обратите внимание, что в версии jsBin я также добавил пользовательское исключение для пустых значений. Это необязательно, и поэтому я оставил это из минимального определения выше.

Улучшения приветствуются