aboutsummaryrefslogtreecommitdiff
path: root/files/uk/web/javascript/reference/operators/optional_chaining/index.html
blob: 3cac80cca80dd1b3a6fd55549140c80abd105bc1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
---
title: Необов'язкове ланцюгування
slug: Web/JavaScript/Reference/Operators/Optional_chaining
tags:
  - JavaScript
  - Optional chaining
  - Експериментальний
  - Оператор
translation_of: Web/JavaScript/Reference/Operators/Optional_chaining
---
<div>{{jsSidebar("Operators")}}</div>

<div>{{SeeCompatTable}}</div>

<div></div>

<p>Оператор <strong>необов'язкового ланцюгування</strong> <strong><code>?.</code></strong> дозволяє читати значення властивості, розташованої глибоко всередині ланцюга пов'язаних об'єктів, без необхідності прямо підтверджувати, що кожне посилання у ланцюгу є дійсним. <span class="seoSummary">Оператор <code>?.</code> діє схоже з оператором ланцюгування <code>.</code>, за винятком того, що замість помилки у випадку посилання на {{jsxref("null")}} чи {{jsxref("undefined")}}, вираз виконає коротке замикання та поверне <code>undefined</code>.</span> При використанні з викликами функцій, вираз поверне <code>undefined</code>, якщо задана функція не існує.</p>

<p>Це створює коротші та простіші вирази для звернення через ланцюг властивостей, коли існує ймовірність зустріти відсутнє посилання. Це також може бути корисним для дослідження вмісту об'єкта, коли немає гарантії того, що певні властивості є обов'язковими.</p>

<div>{{EmbedInteractiveExample("pages/js/expressions-optionalchainingoperator.html")}}</div>

<div></div>



<h2 id="Синтаксис">Синтаксис</h2>

<pre class="syntaxbox"><var>obj</var>?.<var>prop</var>
<var>obj</var>?.[<var>expr</var>]
arr?.[index]
<var>func</var>?.(<var>args</var>)
</pre>

<h2 id="Опис">Опис</h2>

<p>Оператор необов'язкового ланцюгування надає спосіб спростити звернення до значень через поєднані об'єкти, коли є ймовірність, що посилання чи функція дорівнюватиме <code>undefined</code> чи <code>null</code>.</p>

<p>Наприклад, розглянемо об'єкт <code>obj</code>, який має вкладену структуру. Без необов'язкового ланцюгування пошук глибоко вкладеної властивості вимагає перевірки проміжних посилань, як от:</p>

<pre class="brush: js">let nestedProp = obj.first &amp;&amp; obj.first.second;</pre>

<p>Підтверджуємо, що значення <code>obj.first</code> не <code>null</code> (і не <code>undefined</code>) перед тим, як звертатись до <code>obj.first.second</code>. Це дозволяє запобігти помилці, яка виникла б, якщо б ми просто звернулись прямо до <code>obj.first.second</code> без перевірки <code>obj.first</code>.</p>

<p>Проте, з оператором необов'язкового ланцюгування (<code>?.</code>) ви не мусите робити явну перевірку та переривати вираз в залежності від стану <code>obj.first</code> перед тим, як звертатись до <code>obj.first.second</code>:</p>

<pre class="brush: js">let nestedProp = obj.first?.second;</pre>

<p>При використанні оператора <code>?.</code> замість простого <code>.</code> JavaScript виконує неявну перевірку, щоб переконатись, що <code>obj.first</code> не дорівнює <code>null</code> чи <code>undefined</code>, перед тим, як звертатись до <code>obj.first.second</code>. Якщо <code>obj.first</code> дорівнює <code>null</code> чи <code>undefined</code>, вираз автоматично виконує коротке замикання, повертаючи <code>undefined</code>.</p>

<p>Це еквівалентно наступному:</p>

<pre class="brush: js">let nestedProp = ((obj.first == null || obj.first == undefined) ? undefined : obj.first.second);</pre>

<h3 id="Необовязкове_ланцюгування_з_викликами_функцій">Необов'язкове ланцюгування з викликами функцій</h3>

<p>Ви можете скористатись необов'язковим ланцюгуванням під час виклику методу, який, можливо, не існує. Це може бути зручно, наприклад, при використанні API, у якому метод може бути недоступний, чи то через застарілу реалізацію, чи тому, що функціональність недоступна на пристрої користувача.</p>

<p>При використанні необов'язкового ланцюгування, вираз автоматично повертає <code>undefined</code> замість викидання винятку, якщо метод не знайдений:</p>

<pre class="brush: js">let result = someInterface.customMethod?.();</pre>

<div class="blockIndicator note">
<p><strong>Заувага:</strong> Якщо існує властивість з таким іменем, яка не є функцією, використання <code>?.</code> все ж спричинить виняток {{jsxref("TypeError")}} (<code>x.y</code><code> is not a function</code>).</p>
</div>

<h4 id="Необовязкові_зворотні_виклики_та_обробники_подій">Необов'язкові зворотні виклики та обробники подій</h4>

<p>Якщо ви використовуєте зворотні виклики або методи fetch з об'єкта з <a href="/uk/docs/Web/JavaScript/Reference/Operators/%D0%94%D0%B5%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D1%96%D1%8F#%D0%94%D0%B5%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D1%96%D1%8F_%D0%BE%D0%B1%E2%80%99%D1%94%D0%BA%D1%82%D1%96%D0%B2">деструктуризаційним присвоєнням</a>, ви, можливо, матимете неіснуючі значення, які не можна викликати як функції, поки ви не перевірили, що вони існують. Використовуючи <code>?.</code>, можна уникнути цієї додаткової перевірки:</p>

<pre class="brush: js">// Написано згідно ES2019
function doSomething(onContent, onError) {
  try {
    // ... використати дані
  }
  catch (err) {
    if (onError) { // Перевірка, що onError існує
      onError(err.message);
    }
  }
}
</pre>

<pre class="brush: js">// Використання необов'язкового ланцюгування з викликами функцій
function doSomething(onContent, onError) {
  try {
   // ... використати дані
  }
  catch (err) {
    onError?.(err.message); // жодного винятку, якщо onError є undefined
  }
}
</pre>

<h3 id="Необовязкове_ланцюгування_з_виразами">Необов'язкове ланцюгування з виразами</h3>

<p>Ви також можете використати оператор необов'язкового ланцюгування, звертаючись до властивостей через вираз з використанням <a href="/uk/docs/Web/JavaScript/Reference/Operators/Property_Accessors#Bracket_notation">дужкової нотації</a>:</p>

<pre class="brush: js">let nestedProp = obj?.['prop' + 'Name'];
</pre>

<h3 id="Доступ_до_елементу_масиву_через_необовязкове_ланцюгування">Доступ до елементу масиву через необов'язкове ланцюгування</h3>

<pre class="brush: js">let arrayItem = arr?.[42];</pre>

<h2 id="Приклади">Приклади</h2>

<h3 id="Базовий_приклад">Базовий приклад</h3>

<p>Цей приклад звертається до значення властивості <code>name</code> ключа <code>bar</code> у мапі, де немає такого ключа. Отже, результатом буде <code>undefined</code>.</p>

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

let nameBar = myMap.get("bar")?.name;</pre>

<h3 id="Коротке_замикання_обчислення">Коротке замикання обчислення</h3>

<p>При використанні необов'язкового ланцюгування з виразами, якщо лівий операнд дорівнює <code>null</code> чи <code>undefined</code>, вираз не буде обчислюватись. Для прикладу:</p>

<pre class="brush: js">let potentiallyNullObj = null;
let x = 0;
let prop = potentiallyNullObj?.[x++];

console.log(x); // 0, оскільки значення x не збільшувалось
</pre>

<h3 id="Складання_операторів_необовязкового_ланцюгування">Складання операторів необов'язкового ланцюгування</h3>

<p>У вкладених структурах можна використовувати необов'язкове ланцюгування декілька раз:</p>

<pre class="brush: js">let customer = {
  name: "Карл",
  details: {
    age: 82,
    location: "Далекі гори" // точна адреса невідома
  }
};
let customerCity = customer.details?.address?.city;

// … це також працює для ланцюгування виклику функції
let duration = vacations.trip?.getTime?.();
</pre>

<h3 id="Поєднання_з_оператором_null-обєднання">Поєднання з оператором null-об'єднання</h3>

<p>Можна скористатись оператором null-об'єднання після необов'язкового ланцюгування, щоб задати значення, коли воно не було знайдене:</p>

<pre class="brush: js">let customer = {
  name: "Карл",
  details: { age: 82 }
};
let customerCity = customer?.city ?? "Невідоме місто";
console.log(customerCity); // Невідоме місто</pre>

<h2 id="Специфікації">Специфікації</h2>

<table class="standard-table">
 <thead>
  <tr>
   <th scope="col">Специфікація</th>
   <th scope="col">Статус</th>
   <th scope="col">Коментар</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td><a href="https://tc39.es/proposal-optional-chaining/#top">Пропозиція щодо оператора "необов'язкового ланцюгування"</a></td>
   <td>Стадія 4</td>
   <td></td>
  </tr>
 </tbody>
</table>

<h2 id="Сумісність_з_веб-переглядачами">Сумісність з веб-переглядачами</h2>

<p>{{Compat("javascript.operators.optional_chaining")}}</p>

<h2 id="Див._також">Див. також</h2>

<ul>
 <li>{{JSxRef("Operators/Nullish_Coalescing_Operator", "Оператор null-об'єднання", '', 1)}}</li>
 <li><a href="https://github.com/tc39/proposals">TC39 proposals</a></li>
</ul>