Главная » Хабрахабр » [Перевод] Настоящее и будущее безопасной работы с null и undefined в JavaScript

[Перевод] Настоящее и будущее безопасной работы с null и undefined в JavaScript

Автору материала, перевод которого мы сегодня публикуем, недавно попался один вопрос на StackOverflow, который заставил его задуматься об обработке значений null и undefined в JavaScript. Здесь он приводит анализ текущей ситуации, показывает некоторые приёмы безопасной работы с null и undefined, а также, говоря о будущем, рассматривает оператор ?..

image

Основные сведения

Undefined — это примитивное значение, которое автоматически назначается объявленным, но неинициализированным переменным. Это значение можно получить, обратившись к несуществующему свойству объекта или к несуществующему аргументу функции.

Например, если переменной присвоено значение null, это можно трактовать как то, что на данном этапе работы программы эта переменная существует, но у неё пока нет ни типа, ни значения. Null — это ещё одно примитивное значение, которое представляет собой отсутствие значения.

Посмотрим, что произойдёт, если выполнить такой код:

let obj;
console.log(obj.someProp);

Он выдаст следующую ошибку:

TypeError: Cannot read property 'someProp' of undefined

Похожее можно видеть и при попытках работы с переменными, имеющими значение null.

Проверка на null и undefined

Как избежать подобных явлений? К счастью для нас, JavaScript поддерживает вычисление логических выражений по сокращённой схеме (short-circuit evaluation). Это означает, что для того, чтобы избежать вышеописанной ошибки TypeError, можно написать следующий код:

let obj;
console.log(obj && obj.someProp); // вывод undefined

Но что если нужно пойти глубже, например, добраться до чего-то вроде obj.prop1.prop2.prop3? В подобной ситуации можно попытаться решить задачу, выполнив множество проверок:

console.log( obj && obj.prop1 && obj.prop1.prop2 && obj.prop1.prop2.prop3 );

Хотя это и работает, смотрятся такие конструкции не очень-то хорошо.

Это возможно, но тогда кода придётся писать ещё больше: А что если нам нужно выводить некое стандартное значение, если в подобной цепочке встречается undefined или null?

const evaluation = obj && obj.prop1 && obj.prop1.prop2 && obj.prop1.prop2.prop3; console.log( evaluation != null ? evaluation : "SomeDefaultValue" );

Прежде чем продолжить размышления о null и undefined в JavaScript, поговорим о том, как подобные значения обрабатываются в других языках.

Другие языки

Надо отметить, что проблема работы с неопределёнными значениями присутствует в большинстве языков программирования. Посмотрим, как проводятся проверки, подобные вышеописанным, в других языках.

▍Java

В Java есть api Optional:

SomeClass object; Optional.ofNullable(object) .map(obj -> obj.prop1) .map(obj -> obj.prop2) .map(obj -> obj.prop3) .orElse("SomeDefaultValue");

▍Kotlin

В Kotlin (он, как и Java, использует JVM) существуют операторы elvis (?:) и safe-call (?.).

val object: SomeClass?
object?.prop1?.prop2?.prop3 ?: "SomeDefaultValue";

▍C#

И, наконец, в C# есть операторы null-condition (?.), и null-coalescing (??).

SomeClass object;
object?.prop1?.prop2?.prop3 ?? "SomeDefaultValue";

Как работать с undefined в JS?

После рассмотрения возможностей по работе с неопределёнными значениями в других языках, я задался вопросом о том, есть ли возможность безопасно работать с undefined в JavaScript и при этом не писать километры кода. Поэтому я приступил к экспериментам с регулярными выражениями. Мне хотелось создать функцию, которая позволила бы безопасно получать доступ к свойствам объектов.

function optionalAccess(obj, path, def) { const propNames = path.replace(/\]|\)/, "").split(/\.|\[|\(/); return propNames.reduce((acc, prop) => acc[prop] || def, obj);
} const obj = ] }; console.log(optionalAccess(obj, "items[0].hello", "def")); // Вывод Hello
console.log(optionalAccess(obj, "items[0].he", "def")); // Вывод def

После того, как я создал эту функцию, я узнал о методе lodash._get, который имеет такую же сигнатуру:

_.get(object, path, [defaultValue])

Однако, честно говоря, я не отношусь к фанатам строковых путей, поэтому я начал искать способ, который позволил бы избежать их использования. В результате я создал решение, основанное на прокси-объектах:

// Именно здесь происходит всё самое интересное
function optional(obj, evalFunc, def) { // Обработчик прокси const handler = { // Перехват всех операций доступа к свойствам get: function(target, prop, receiver) { const res = Reflect.get(...arguments); //Если наш ответ является объектом, обернём его в прокси, иначе - просто вернём return typeof res === "object" ? proxify(res) : res != null ? res : def; } }; const proxify = target => { return new Proxy(target, handler); }; // Вызовем функцию с проксированным объектом return evalFunc(proxify(obj, handler));
} const obj = { items: [{ hello: "Hello" }] }; console.log(optional(obj, target => target.items[0].hello, "def")); // => Hello
console.log(optional(obj, target => target.items[0].hell, { a: 1 })); // => { a: 1 }

Будущее безопасной работы с null и undefined в JavaScript

Сейчас в комитете TC39 имеется предложение, которое позволяет пользоваться следующими конструкциями:

obj?.arrayProp?[0]?.someProp?.someFunc?.();

По мне, так выглядит это очень аккуратно. Однако это предложение пока находится на достаточно ранней стадии согласования, то есть, его потенциальное появление в языке может занять некоторое время. Но, несмотря на это, существует плагин для babel, который позволяет уже сегодня пользоваться подобными конструкциями.

Итоги

Значения вроде null и undefined присутствуют в программировании уже очень давно, и ничто не указывает на то, что они в скором времени исчезнут. Вероятно, концепция значения null является самой нелюбимой в программировании, однако у нас есть средства для обеспечения безопасной работы с подобными значениями. В том, что касается работы с null и undefined в JavaScript, можно воспользоваться несколькими подходами рассмотренными выше. В частности, вот код функций, предложенных автором этого материала. Если вас заинтересовал оператор ?., появление которого ожидается в JS, взгляните на одну из наших предыдущих публикаций, в которой затрагивается этот вопрос.

Уважаемые читатели! Какой из упомянутых в этом материале способов безопасной работы с null и undefined в JavaScript нравится вам больше всего?


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

Частичка программы HolyJS 2018 Moscow

Конференция состоится 24–25 ноября. HolyJS 2018 Moscow уже совсем скоро. В этот раз программа получилась весьма разнообразной, однако несложно выделить главные тенденции: Доклады из первых рук (#firsthand) — доклады о инструментах/решениях от их авторов. Мы особенно тщательно подошли к выбору ...

[Перевод] GPU консоли Nintendo DS и его интересные особенности

Я хотел бы рассказать вам о работе GPU консоли Nintendo DS, об его отличиях от современных GPU, а также выразить своё мнение о том, почему использование Vulkan вместо OpenGL в эмуляторах не принесёт никаких преимуществ. Это может пригодиться для эмуляции ...