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

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

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

Синтаксис

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

Описание

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

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

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

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

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

let nestedProp = obj.first?.second;

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

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

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

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

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

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

let result = someInterface.customMethod?.();

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

Работа с функциями обратного вызова и обработчиками событий

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

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

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

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

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

Примеры

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Спецификация Статус Примечание
Proposal for the "optional chaining" operator Stage 4

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

Update compatibility data on GitHub
КомпьютерыМобильныеServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome для AndroidFirefox для AndroidOpera для AndroidSafari on iOSSamsung InternetNode.js
Optional chaining operator (?.)Chrome Полная поддержка 80
Полная поддержка 80
Полная поддержка 79
Отключено
Отключено From version 79: this feature is behind the Experimental JavaScript preference (needs to be set to true). To change preferences in Chrome, visit chrome://flags.
Edge Полная поддержка 80
Полная поддержка 80
Полная поддержка 79
Отключено
Отключено From version 79: this feature is behind the Experimental JavaScript preference (needs to be set to true).
Firefox Полная поддержка 74IE Нет поддержки НетOpera Полная поддержка 67
Полная поддержка 67
Полная поддержка 66
Отключено
Отключено From version 66: this feature is behind the Experimental JavaScript preference (needs to be set to true).
Safari Полная поддержка 13.1WebView Android Полная поддержка 80Chrome Android Полная поддержка 80
Полная поддержка 80
Полная поддержка 79
Отключено
Отключено From version 79: this feature is behind the Experimental JavaScript preference (needs to be set to true). To change preferences in Chrome, visit chrome://flags.
Firefox Android Нет поддержки НетOpera Android Нет поддержки НетSafari iOS Полная поддержка 13.4Samsung Internet Android Нет поддержки Нетnodejs Полная поддержка 14.0.0

Легенда

Полная поддержка  
Полная поддержка
Нет поддержки  
Нет поддержки
Пользователь должен сам включить эту возможность.
Пользователь должен сам включить эту возможность.

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