Необязательная цепочка в JavaScript
В последнее время я много программировал на Swift. Сегодня я выполнил некоторую работу в JavaScipt, когда у меня возник вопрос:
Есть ли что-то похожее на необязательную цепочку в JavaScript? Способ предотвратить undefined is not an object
без каких-либо переменных?
Пример:
function test(){
if(new Date() % 2){
return {value: function(){/*code*/}};
}
}
test().value();
провалит половину времени, потому что иногда test
возвращает неопределенное.
Единственное решение, которое я могу придумать, это функция:
function oc(object, key){
if(object){
return object[key]();
}
}
oc(test(), 'value');
Я хотел бы иметь возможность сделать что-то вроде:
test()?.value()
Часть после знака вопроса выполняется только в том случае, если test
вернул объект.
Но это не очень элегантно. Есть ли что-то лучше? Волшебная комбинация операторов?
Изменить Я знаю, что я мог бы переписать test
вернуть что-то. Но мне интересно, есть ли что-то вроде необязательной цепочки. Я не заинтересован в конкретном решении приведенного выше примера. Что-то, что я также могу использовать, если не имею контроля над функцией, возвращающей undefined.
5 ответов
В простом JavaScript вы должны проверять тип или структурировать свой код так, чтобы вы знали, что объект будет существовать.
CoffeeScript, язык, который компилируется в JavaScript, предоставляет экзистенциальный оператор ?.
для безопасной цепочки, если вы хотите рассмотреть предварительно обработанный язык.
Здесь еще одна дискуссия о том, почему вы не можете воспроизвести это поведение в JS.
На форумах ESDiscuss также обсуждается вопрос о добавлении экзистенциального оператора в будущую версию JavaScript. Это, кажется, не очень далеко впереди, конечно, далеко не близко к практическому использованию. Больше идей на данный момент.
В настоящее время это предложение стадии 1, вы можете проверить его ход здесь:
Вы можете использовать плагин 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-optional-chaining
Также стоит проверить:
Необязательная цепочка появилась в JS. Мы можем использовать необязательную цепочку через?.
оператор в доступе к свойствам объекта. Это позволяет нам попробовать получить доступ к свойствам объектов, которые могут не существовать (т.е.undefined
) без выдачи ошибки.
Вот пример кода:
const obj = {
foo: {
bar: 1
}
};
// If we try to access property which doesn't exists
// it just returns undefined
console.log(obj.baz);
try {
// Now we try to access a property of undefined which throws an error
obj.baz.foz;
} catch (e) {
console.dir(e.message);
}
// Now we use the optional chaining operator ?.
// We get undefined instead of an error
console.log(obj.baz?.foz);
console.log(obj.foo?.bar);
Ты можешь использовать
test() && test().value();
или же
var testResult = test();
testResult && testResult.value();
Если вы спросите меня, это больше всего похоже на необязательную цепочку Swift.
Необязательная цепочка наконец-то появилась в стандарте JavaScript!
Вот несколько примеров:
// properties
foo?.bar
foo?.bar()
foo?.bar.baz()
foo?.bar?.baz()
// indexing
foo?.[0]
foo?.['bar']
// check if a function is defined before invoking
foo?.()
foo.bar?.()
foo?.bar?.()
И это намного лучше, чем то, что большинство людей используют для ручной проверки нулей.
Вместо того, чтобы оценивать
foo?.bar
к этому небольшому фрагменту кода, который мы все привыкли писать
foo ? foo.bar : null
это фактически оценивается как
foo == null ? undefined : foo.bar
который работает для всех значений falsey, таких как пустая строка, 0 или false.
Не имеет отношения к вопросу, но вас также может заинтересовать ??
оператор.
Он имеет ту же цель, что и ||
за исключением того, что он проверяет только null или undefined.
Например:
foo ?? bar
будет таким же, как:
foo != null ? foo : bar
Это очень новая функция, поэтому даже при том, что многие пользователи уже используют браузер, который ее поддерживает, вы все равно захотите использовать инструмент для преобразования его в старую версию javascript.
var Obj = {Prop: {name: 'peter'}}
console.log(Obj.Prop.name)
console.log(Obj?.Prop?.name)
В первом предложении вы просто обращаетесь к свойствам объекта. Проблема в том, что если вы найдетеProp
чтобы быть чем-то другим, кроме объекта, он вызовет исключение. Это причина необязательного оператора цепочки.
Допустим, вы пытаетесь сделать Obj.Prop2.name
. Ты получишьUncaught TypeError: Cannot read property 'name' of undefined
если вместо этого вы сделали Obj.Prop2?.name
, Вы получите только undefined
как значение, а не исключение.
Это особенно полезно при доступе к глубоко вложенным свойствам.
ВНИМАНИЕ: это относительно новая функция JS, которая еще не реализована во всех браузерах, поэтому будьте осторожны при ее использовании для производственных приложений.
Как насчет возврата функции noop, которая ничего не делает, когда условие не выполняется?
function test(){
if(new Date() % 2){
return {value: function(){/*code*/}};
}
return {value: function(){ /* just return a type consistent with the function above */ }
}
Вы всегда можете return this;
если тест это объектный метод.
Но почему вы хотите предотвратить такие ошибки, создавая фиктивные функции?