Опциональная цепочка (?.)
Базовый уровень Широко доступно
Эта функция хорошо зарекомендовала себя и работает на многих устройствах и версиях браузеров. Она доступна во всех браузерах с июля 2015 года.
Оператор опциональной цепочки (?.) обращается к свойству объекта или вызывает функцию. Если объект, к которому происходит обращение, или функция, которая вызывается с помощью этого оператора, является undefined или null, выражение немедленно завершается (short circuits) и принимает значение undefined вместо того, чтобы вызвать ошибку.
Попробуйте
const adventurer = {
name: "Alice",
cat: {
name: "Dinah",
},
};
const dogName = adventurer.dog?.name;
console.log(dogName);
// Expected output: undefined
console.log(adventurer.someNonExistentMethod?.());
// Expected output: undefined
Синтаксис
obj?.prop obj?.[expr] func?.(args)
Описание
Оператор ?. похож на оператор цепочки ., за исключением того, что вместо возникновения ошибки, если ссылка является нуллиш-значением (null или undefined), выражение немедленно завершается (short-circuits) с возвращаемым значением undefined. При использовании с вызовами функций он возвращает undefined, если данная функция не существует.
Это приводит к более коротким и простым выражениям при обращении к связанным свойствам, когда существует вероятность того, что ссылка может отсутствовать. Это также может быть полезно при изучении содержимого объекта, когда нет известной гарантии относительно того, какие свойства требуются.
Например, рассмотрим объект obj, который имеет вложенную структуру. Без опциональной цепочки поиск глубоко вложенного под-свойства требует проверки промежуточных ссылок, например:
const nestedProp = obj.first && obj.first.second;
Значение obj.first подтверждается как не-null (и не-undefined) перед доступом к значению obj.first.second. Это предотвращает ошибку, которая возникла бы, если бы вы обращались к obj.first.second напрямую, не проверяя obj.first.
Это идиоматический шаблон в JavaScript, но он становится многословным, когда цепочка длинная, и небезопасен. Например, если obj.first является Falsy значением, которое не является null или undefined, например, 0, оно всё равно немедленно завершится и сделает nestedProp равным 0, что может быть нежелательно.
Однако с оператором опциональной цепочки (?.) вам не нужно явно проверять и немедленно завершать выполнение на основе состояния obj.first, прежде чем пытаться получить доступ к obj.first.second:
const nestedProp = obj.first?.second;
Используя оператор ?. вместо просто ., JavaScript знает, что нужно неявно проверить, не является ли obj.first значением null или undefined, прежде чем пытаться получить доступ к obj.first.second. Если obj.first является null или undefined, выражение автоматически немедленно завершается, возвращая undefined.
Это эквивалентно следующему, за исключением того, что временная переменная фактически не создается:
const temp = obj.first; const nestedProp = temp === null || temp === undefined ? undefined : temp.second;
Опциональная цепочка не может использоваться на необъявленном корневом объекте, но может использоваться с корневым объектом со значением undefined.
undeclaredVar?.prop; // ReferenceError: undeclaredVar is not defined
Опциональная цепочка с вызовами функций
Вы можете использовать опциональную цепочку при попытке вызвать метод, который может не существовать. Это может быть полезно, например, при использовании API, в котором метод может быть недоступен либо из-за давности реализации, либо из-за функции, которая недоступна на устройстве пользователя.
Использование опциональной цепочки с вызовами функций приводит к тому, что выражение автоматически возвращает undefined вместо того, чтобы генерировать исключение, если метод не найден:
const result = someInterface.customMethod?.();
Однако, если существует свойство с таким именем, которое не является функцией, использование ?. по-прежнему вызовет исключение TypeError "someInterface.customMethod is not a function".
Примечание: Если сам someInterface является null или undefined, исключение TypeError всё равно будет сгенерировано ("someInterface is null"). Если вы ожидаете, что сам someInterface может быть null или undefined, вам также необходимо использовать ?. в этой позиции: someInterface?.customMethod?.().
eval?.() — это самый короткий способ войти в режим непрямого eval.
Опциональная цепочка с выражениями
Вы также можете использовать оператор опциональной цепочки с скобочной нотацией, которая позволяет передавать выражение в качестве имени свойства:
const propName = "x"; const nestedProp = obj?.[propName];
Это особенно полезно для массивов, так как доступ к индексам массива должен осуществляться с помощью квадратных скобок.
function printMagicIndex(arr) {
console.log(arr?.[42]);
}
printMagicIndex([0, 1, 2, 3, 4, 5]); // undefined
printMagicIndex(); // undefined; if not using ?., this would throw an error: "Cannot read properties of undefined (reading '42')"
Недопустимая опциональная цепочка
Недопустимо пытаться присвоить значение результату выражения опциональной цепочки:
const object = {};
object?.property = 1; // SyntaxError: Invalid left-hand side in assignment
Теги шаблонных литералов не могут быть опциональной цепочкой (см. SyntaxError: tagged template cannot be used with optional chain):
String?.raw`Hello, world!`; String.raw?.`Hello, world!`; // SyntaxError: Invalid tagged template on optional chain
Конструктор выражений new не может быть опциональной цепочкой (см. SyntaxError: new keyword cannot be used with an optional chain):
new Intl?.DateTimeFormat(); // SyntaxError: Invalid optional chain from new expression new Map?.();
Немедленное завершение (Short-circuiting)
При использовании опциональной цепочки с выражениями, если левый операнд является null или undefined, выражение не будет вычислено. Например:
const potentiallyNullObj = null; let x = 0; const prop = potentiallyNullObj?.[x++]; console.log(x); // 0 as x was not incremented
Последующие обращения к свойствам также не будут вычисляться.
const potentiallyNullObj = null; const prop = potentiallyNullObj?.a.b; // This does not throw, because evaluation has already stopped at // the first optional chain
Это эквивалентно:
const potentiallyNullObj = null;
const prop =
potentiallyNullObj === null || potentiallyNullObj === undefined
? undefined
: potentiallyNullObj.a.b;
Однако такое поведение немедленного завершения происходит только в рамках одной непрерывной «цепочки» обращений к свойствам. Если вы группируете одну часть цепочки, то последующие обращения к свойствам всё равно будут вычислены.
const potentiallyNullObj = null; const prop = (potentiallyNullObj?.a).b; // TypeError: Cannot read properties of undefined (reading 'b')
Это эквивалентно:
const potentiallyNullObj = null; const temp = potentiallyNullObj?.a; const prop = temp.b;
За исключением того, что переменная temp не создается.
Примеры
Базовый пример
В этом примере ищется значение свойства name для элемента CSS в сопоставлении (map), когда такого элемента нет. Следовательно, результатом является undefined.
const myMap = new Map();
myMap.set("JS", { name: "Josh", desc: "I maintain things" });
const nameBar = myMap.get("CSS")?.name;
Работа с опциональными колбэками или обработчиками событий
Если вы используете колбэки или методы выборки из объекта с помощью деструктуризации, у вас могут быть несуществующие значения, которые вы не сможете вызвать как функции, если вы не проверили их существование. Используя ?., вы можете избежать этой дополнительной проверки:
// Code written without optional chaining
function doSomething(onContent, onError) {
try {
// Do something with the data
} catch (err) {
// Testing if onError really exists
if (onError) {
onError(err.message);
}
}
}
// Using optional chaining with function calls
function doSomething(onContent, onError) {
try {
// Do something with the data
} catch (err) {
onError?.(err.message); // No exception if onError is undefined
}
}
Наслаивание оператора опциональной цепочки
При наличии вложенных структур можно использовать опциональную цепочку несколько раз:
const customer = {
name: "Carl",
details: {
age: 82,
location: "Paradise Falls", // Detailed address is unknown
},
};
const customerCity = customer.details?.address?.city;
// This also works with optional chaining function call
const customerName = customer.name?.getName?.(); // Method does not exist, customerName is undefined
Комбинирование с оператором объединения с nullish
Оператор объединения с nullish может использоваться после опциональной цепочки для создания значения по умолчанию, если ничего не было найдено:
function printCustomerCity(customer) {
const customerCity = customer?.city ?? "Unknown city";
console.log(customerCity);
}
printCustomerCity({
name: "Nathan",
city: "Paris",
}); // "Paris"
printCustomerCity({
name: "Carl",
details: { age: 82 },
}); // "Unknown city"
Спецификации
Совместимость с браузерами
| Десктопные | Мобильные | Серверные | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox for Android | Opera Android | Safari on iOS | Samsung Internet | WebView Android | WebView on iOS | Bun | Deno | Node.js | |
optional_chaining |
80Вызов с нефинальным spread-аргументом в опциональной цепочке завершается ошибкой в Chrome с 80 по 90 версию. См. bug 42201552. |
80Вызов с нефинальным spread-аргументом в опциональной цепочке завершается ошибкой в Edge с 80 по 90 версию. См. bug 42201552. |
74 |
67Вызов с нефинальным spread-аргументом в опциональной цепочке завершается ошибкой в Opera с 67 по 90 версию. См. bug 42201552. |
13.1 |
80Вызов с нефинальным spread-аргументом в опциональной цепочке завершается ошибкой в Chrome Android с 80 по 90 версию. См. bug 42201552. |
79 |
57Вызов с нефинальным spread-аргументом в опциональной цепочке завершается ошибкой в Opera Android с 57 по 90 версию. См. bug 42201552. |
13.4 |
13.0Вызов с нефинальным spread-аргументом в опциональной цепочке завершается ошибкой в Samsung Browser с 13.0 по 90 версию. См. bug 42201552. |
80Вызов с нефинальным spread-аргументом в опциональной цепочке завершается ошибкой в WebView Android с 80 по 90 версию. См. bug 42201552. |
13.4 |
1.0.0 |
1.0 |
14.0.0 |
Смотрите также
© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining