Оператор опциональной последовательности

Оператор опциональной последовательности ?. позволяет получить значение свойства, находящегося на любом уровне вложенности в цепочке связанных между собой объектов, без необходимости проверять каждое из промежуточных свойств в ней на существование. ?. работает подобно оператору ., за исключением того, что не выбрасывает исключение, если объект, к свойству или методу которого идёт обращение, равен null или undefined. В этих случаях он возвращает undefined.

Таким образом, мы получаем более короткий и понятный код при обращении к вложенным по цепочке свойствам объекта, когда есть вероятность, что какое-то из них отсутствует.

Интерактивный пример

Синтаксис

js
obj?.prop;
obj?.[expr];
arr?.[index];
func?.(args);

Описание

Оператор опциональной последовательности предоставляет способ упростить доступ к значениям в цепочке объектов, когда возможно, что какое-то свойство (или метод) в ней равно undefined или null.

Для примера, создадим объект obj, имеющий вложенную структуру. Без оператора опциональной последовательности поиск глубоко расположенных подсвойств требует проверки всех промежуточных свойств на существование, например:

js
let nestedProp = obj.first && obj.first.second;

Если обращаться к obj.first.second без проверки obj.first, то, если свойство obj.first равно null или undefined, выбросится исключение TypeError.

Однако, с оператором опциональной последовательности (?.) не требуется явно проверять ссылку на obj.first перед обращением к obj.first.second:

js
let nestedProp = obj.first?.second;

Если используется оператор ?. вместо ., JavaScript знает о необходимости проверки obj.first перед обращением к obj.first.second. Если значение obj.first равно null или undefined, выполнение выражения автоматически прекращается и возвращается undefined.

Это эквивалентно следующему (кроме создания временной переменной):

js
let temp = obj.first;
let nestedProp = temp === null || temp === undefined ? undefined : temp.second;

Опциональная последовательность с вызовом функции

Вы можете использовать ?., когда необходимо вызвать метод, которого может не существовать. Это может быть полезно, например, при использовании API, в котором метод может быть недоступен из-за устаревания или не поддерживаемости устройством пользователя.

Использование ?. с вызовом функции значит, что выполнение автоматически вернёт undefined, а не выбросит исключение, если метод не найден:

js
let result = someInterface.customMethod?.();

Примечание: Для существующего свойства, не являющегося функцией, использование конструкции x.y?.() всё равно выбросит TypeError исключение (x.y не является функцией).

Работа с колбэк-функциями и обработчиками событий

Если вы используете колбэк-функции или извлекаете методы объекта деструктурирующим присваиванием, Вы можете получить несуществующие значения, которые нельзя вызывать как функции до проверки на их существование. Используя оператор ?., вы можете избежать лишних проверок:

js
// С использованием ES2019
function doSomething(onContent, onError) {
  try {
    // ... делаем что-то с данными
  } catch (err) {
    if (onError) {
      // проверяем, существует ли onError
      onError(err.message);
    }
  }
}
js
// С использованием оператора опциональной последовательности
function doSomething(onContent, onError) {
  try {
    // ... делаем что-то с данными
  } catch (err) {
    onError?.(err.message); // не выбросит исключение, если onError равен undefined
  }
}

Опциональные последовательности в выражениях

Вы также можете использовать оператор опциональной последовательности, когда обращаетесь к свойству с помощью скобочной нотации:

js
let nestedProp = obj?.["prop" + "Name"];

Примеры

Базовый пример

В этом примере производится обращение к свойству name элемента с ключом bar объекта Map. Элемент с таким ключом отсутствует, но исключение выброшено не будет; nameBar равен undefined.

js
let myMap = new Map();
myMap.set("foo", { name: "baz", desc: "inga" });

let nameBar = myMap.get("bar")?.name;

Сокращённое выполнение

При использовании оператора опциональной последовательности в выражениях, где левая часть операнда равна null или undefined, выражение не будет выполнено. Например:

js
let potentiallyNullObj = null;
let x = 0;
let prop = potentiallyNullObj?.[x++];

console.log(x); // 0, т.к. x не был инкрементирован

Совместное использование операторов опциональной последовательности

Во вложенных объектах возможно использование оператора опциональной последовательности неограниченное количество раз:

js
let customer = {
  name: "Carl",
  details: {
    age: 82,
    location: "Paradise Falls", // точный адрес неизвестен
  },
};
let customerCity = customer.details?.address?.city;

// … это также работает с вызовами функций
let duration = vacations.trip?.getTime?.();

Использование с оператором ??

Оператор ?? может использоваться после опциональной последовательности для установления значения по умолчанию:

js
let customer = {
  name: "Carl",
  details: { age: 82 },
};
const customerCity = customer?.city ?? "Unknown city";
console.log(customerCity); // Unknown city

Спецификации

Specification
ECMAScript Language Specification
# prod-OptionalExpression

Совместимость с браузерами

BCD tables only load in the browser

Смотрите также