Опциональная цепочка
Представьте цепочку карточек: от анкеты пользователя к карточке с адресом, а от неё — к городу. У одних пользователей карточка с адресом есть, у других нет. Если карточки нет, искать в ней строку «Город» не получится.
Программа в таком случае останавливается:
const user = { name: "Ann" };
console.log(user.address); // undefined
console.log(user.address.city); // ✗TypeError: Cannot read properties of undefined (reading 'city')Давайте разберём, что произошло:
user.addressдаётundefined: свойстваaddressнет, но это ещё не ошибка.user.address.cityчитает.cityуundefined. Уundefinedсвойств нет, и чтение.cityуже ошибка.
То же случится со значением null. Проверка через if перед каждой точкой сделала бы код длинным: if (user.address !== undefined) для каждого звена.
Оператор ?.
Опциональная цепочка — оператор ?. вместо точки. Если значение слева от ?. равно null или undefined, всё выражение даёт undefined, и ошибки нет. Иначе ?. читает свойство, как обычная точка:
const ann = { name: "Ann" };
const bob = { name: "Bob", address: { city: "Oslo" } };
console.log(ann.address?.city); // undefined
console.log(bob.address?.city); // Oslo
console.log(ann.address?.city ?? "unknown"); // unknownРазберём по строкам:
- У
annадреса нет:ann.addressравноundefined, и?.останавливает чтение. - У
bobадрес есть, и?.cityчитает город, как обычная точка. - Последняя строка подставляет
"unknown"вместоundefined.
В картотеке ?. похож на осторожного помощника. Он заглядывает в ящик, и если карточки там нет, отвечает «нет данных» вместо того, чтобы искать строку в пустоте.
Ещё две формы той же записи:
- цепочка может проверять несколько звеньев:
order?.client?.address; - для ключа из переменной есть запись со скобками:
user.address?.[field].
Запасное значение через ??
Оператор ?? подставляет запасное значение, когда цепочка дала undefined. Здесь нужен именно ??, а не ||: с || пустая строка или 0 в свойстве тоже заменились бы запасным значением.
Разницу между ?? и || часто спрашивают на собеседовании. || заменяет любое ложное значение, а ?? — только null и undefined.
Возьмём квартиру на нулевом этаже: const flat = { floor: 0 }. Запись flat?.floor ?? 1 даёт 0, как и записано в данных. Запись flat?.floor || 1 даёт 1: оператор || принял ноль за отсутствие значения, и этаж потерялся.
Где остановится цепочка
Когда ?. встречает undefined, остаток цепочки справа не вычисляется: ann.address?.city.length тоже даёт undefined, без ошибки.
Почему нет ошибки на .length? ?. обрывает не одно звено, а всю цепочку справа от себя. Помощник, не найдя карточки, не идёт дальше по цепочке, а сразу возвращает ответ.
Когда ставить ?.
Ставьте ?. только там, где значения может не быть по смыслу данных. Если свойство обязано быть, обычная точка честно сообщит об ошибке, а ?. спрячет её за undefined.
Здесь аналогия с помощником перестаёт работать: через ?. можно только читать. Присваивать через ?. нельзя: user?.name = "Bob" — это SyntaxError.
Частая ошибка
?. поставили не на то звено цепочки:
const user = { name: "Ann" };
console.log(user?.address.city); // ✗TypeError: Cannot read properties of undefined (reading 'city')?. проверяет только значение слева от себя. Здесь это user, а он существует, поэтому чтение идёт дальше, и .city читается у undefined.
Знак нужен после того свойства, которого может не быть: user.address?.city. Если сообщение то же, что и без ?., проверка стоит не на том звене.
Главное
a?.bдаётundefined, еслиaравноnullилиundefined, а иначе читаетb, как точка.- Как только
?.встречаетnullилиundefined, остаток цепочки справа не вычисляется. ??подставляет запасное значение только вместоnullиundefined, не трогая0и пустую строку.?.ставят сразу после того звена, которого может не быть.
Подпишись, чтобы пройти курс
Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.