Необязательная цепочка в JavaScript

Я очень много программировал в Swift. Сегодня я работал над JavaScipt, когда у меня возник вопрос:

Есть ли что-то похожее на необязательную цепочку в JavaScript? Способ предотвращения undefined is not an object без каких-либо переменных?

Пример:

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

test().value();

не удастся выполнить половину времени, потому что иногда test возвращает undefined.

Единственное решение, о котором я могу думать, это функция:

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

oc(test(), 'value');

Я хотел бы сделать что-то вроде:

test()?.value()

Часть после вопросительного знака выполняется только в том случае, если test возвратил объект.

Но это не очень похоже. Есть что-то лучше? Волшебное сочетание операторов?

Изменить Я знаю, что могу переписать test, чтобы вернуть что-то. Но мне интересно, есть ли что-то вроде дополнительной цепочки. Меня не интересует конкретное решение вышеприведенного примера. То, что я также могу использовать, если не имеет никакого контроля над функцией, возвращающей undefined.

Ответ 1

В простом JavaScript вам нужно выполнить проверку типов или структурировать свой код, чтобы вы знали, что объект будет существовать.

CoffeeScript, язык, который скомпилирован с использованием JavaScript, предоставляет экзистенциальный оператор ?. для безопасной цепочки, если вы хотите рассмотреть предварительно обработанный язык.

Здесь еще обсуждается о том, почему вы не можете воспроизвести это поведение в JS.

Существует также обсуждение на форумах ESDiscuss о добавлении экзистенциального оператора в будущую версию JavaScript. Это не очень далеко, хотя, конечно, нигде не приближается к практическому использованию. Больше идеи на данный момент.

Ответ 2

В настоящее время это предложение уровня 3, ход выполнения которого можно посмотреть здесь:
https://github.com/tc39/proposal-optional-chaining

Вы можете использовать плагин Babel сегодня:
https://www.npmjs.com/package/babel-plugin-transform-optional-chaining

Необязательный оператор цепочки пишется ?.. Может отображаться в трех позициях:

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 (как требуется для обратной совместимости), на уровне лексической грамматики добавлена простая "заглядывание", так что последовательность символов?. в этой ситуации не интерпретируется как один токен (за символом?. не должно быть сразу после десятичной цифры).

Также стоит проверить:

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

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

Ответ 3

Вы можете использовать

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

или

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

Если вы спросите меня, это больше похоже на дополнительную цепочку Swift.

Ответ 4

Как насчет возврата функции noop, которая ничего не делает, когда условие не выполняется?

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

Ответ 5

Вы всегда можете return this;, если test является объектным методом.

Но почему вы хотите предотвратить такие ошибки, создавая макетные функции?