--- title: Необов'язкове ланцюгування slug: Web/JavaScript/Reference/Operators/Optional_chaining tags: - JavaScript - Optional chaining - Експериментальний - Оператор translation_of: Web/JavaScript/Reference/Operators/Optional_chaining ---
Оператор необов'язкового ланцюгування ?.
дозволяє читати значення властивості, розташованої глибоко всередині ланцюга пов'язаних об'єктів, без необхідності прямо підтверджувати, що кожне посилання у ланцюгу є дійсним. Оператор ?.
діє схоже з оператором ланцюгування .
, за винятком того, що замість помилки у випадку посилання на {{jsxref("null")}} чи {{jsxref("undefined")}}, вираз виконає коротке замикання та поверне undefined
. При використанні з викликами функцій, вираз поверне undefined
, якщо задана функція не існує.
Це створює коротші та простіші вирази для звернення через ланцюг властивостей, коли існує ймовірність зустріти відсутнє посилання. Це також може бути корисним для дослідження вмісту об'єкта, коли немає гарантії того, що певні властивості є обов'язковими.
obj?.prop obj?.[expr] arr?.[index] func?.(args)
Оператор необов'язкового ланцюгування надає спосіб спростити звернення до значень через поєднані об'єкти, коли є ймовірність, що посилання чи функція дорівнюватиме undefined
чи null
.
Наприклад, розглянемо об'єкт obj
, який має вкладену структуру. Без необов'язкового ланцюгування пошук глибоко вкладеної властивості вимагає перевірки проміжних посилань, як от:
let nestedProp = obj.first && obj.first.second;
Підтверджуємо, що значення obj.first
не null
(і не undefined
) перед тим, як звертатись до obj.first.second
. Це дозволяє запобігти помилці, яка виникла б, якщо б ми просто звернулись прямо до obj.first.second
без перевірки obj.first
.
Проте, з оператором необов'язкового ланцюгування (?.
) ви не мусите робити явну перевірку та переривати вираз в залежності від стану obj.first
перед тим, як звертатись до obj.first.second
:
let nestedProp = obj.first?.second;
При використанні оператора ?.
замість простого .
JavaScript виконує неявну перевірку, щоб переконатись, що obj.first
не дорівнює null
чи undefined
, перед тим, як звертатись до obj.first.second
. Якщо obj.first
дорівнює null
чи undefined
, вираз автоматично виконує коротке замикання, повертаючи undefined
.
Це еквівалентно наступному:
let nestedProp = ((obj.first == null || obj.first == undefined) ? undefined : obj.first.second);
Ви можете скористатись необов'язковим ланцюгуванням під час виклику методу, який, можливо, не існує. Це може бути зручно, наприклад, при використанні API, у якому метод може бути недоступний, чи то через застарілу реалізацію, чи тому, що функціональність недоступна на пристрої користувача.
При використанні необов'язкового ланцюгування, вираз автоматично повертає undefined
замість викидання винятку, якщо метод не знайдений:
let result = someInterface.customMethod?.();
Заувага: Якщо існує властивість з таким іменем, яка не є функцією, використання ?.
все ж спричинить виняток {{jsxref("TypeError")}} (x.y
is not a function
).
Якщо ви використовуєте зворотні виклики або методи fetch з об'єкта з деструктуризаційним присвоєнням, ви, можливо, матимете неіснуючі значення, які не можна викликати як функції, поки ви не перевірили, що вони існують. Використовуючи ?.
, можна уникнути цієї додаткової перевірки:
// Написано згідно 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'];
let arrayItem = arr?.[42];
Цей приклад звертається до значення властивості name
ключа bar
у мапі, де немає такого ключа. Отже, результатом буде 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: "Карл", details: { age: 82, location: "Далекі гори" // точна адреса невідома } }; let customerCity = customer.details?.address?.city; // … це також працює для ланцюгування виклику функції let duration = vacations.trip?.getTime?.();
Можна скористатись оператором null-об'єднання після необов'язкового ланцюгування, щоб задати значення, коли воно не було знайдене:
let customer = { name: "Карл", details: { age: 82 } }; let customerCity = customer?.city ?? "Невідоме місто"; console.log(customerCity); // Невідоме місто
Специфікація | Статус | Коментар |
---|---|---|
Пропозиція щодо оператора "необов'язкового ланцюгування" | Стадія 4 |
{{Compat("javascript.operators.optional_chaining")}}
Наведена нижче таблиця надає щоденний статус реалізації цієї функціональності, оскільки функціональність ще не досягла кросбраузерної стабільності. Дані генеруються запуском відповідних тестів функціональності у Test262, стандартному тестовому наборі JavaScript, на нічній збірці чи на останньому релізі рушія JavaScript кожного веб-переглядача.