aboutsummaryrefslogtreecommitdiff
path: root/files/ru/web/javascript/reference/operators/optional_chaining/index.html
blob: 30fd29e3c0ebf3f987481819b9efa9ad6fba6e15 (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
---
title: "Оператор\_опциональной последовательности"
slug: Web/JavaScript/Reference/Operators/Optional_chaining
translation_of: Web/JavaScript/Reference/Operators/Optional_chaining
---
<div>{{jsSidebar("Operators")}}</div>

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

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

<div>{{EmbedInteractiveExample("pages/js/expressions-optionalchainingoperator.html", "taller")}}</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.second</code> без проверки <code>obj.first</code>, то, если свойство <code>obj.first</code> равно <code>null</code> или <code>undefined</code>, выбросится исключение {{jsxref("TypeError")}}.</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>obj.first.second</code>. Если значение <code>obj.first</code> равно <code>null</code> или <code>undefined</code>, выполнение выражения автоматически прекращается и возвращается <code>undefined</code>.</p>

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

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

<h3 id="Опциональная_последовательность_с_вызовом_функции">Опциональная последовательность с вызовом функции</h3>

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

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

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

<div class="blockIndicator note">
<p><strong>Обратите внимание:</strong> Для существующего свойства, не являющегося функцией, использование конструкции <code>x.y?.()</code> всё равно выбросит {{jsxref("TypeError")}} исключение (<code>x.y не является функцией</code>).</p>
</div>

<h3 id="Работа_с_функциями_обратного_вызова_и_обработчиками_событий">Работа с функциями обратного вызова и обработчиками событий</h3>

<p>Если Вы используете функции обратного вызова или извлекаете методы обьекта <a href="/ru/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Разбор_объектов">деструктурирующим присваиванием</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="/ru/docs/Web/JavaScript/Reference/Operators/Property_Accessors#Скобочная_нотация">скобочной нотации</a>:</p>

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

<h2 id="Примеры">Примеры</h2>

<h3 id="Базовый_пример">Базовый пример</h3>

<p>В этом примере производится обращение к свойству <code>name</code> элемента с ключом <code>bar</code> объекта <code>Map</code>. Элемент с таким ключом отсутствует, но исключение выброшено не будет; <code>nameBar</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: "Carl",
  details: {
    age: 82,
    location: "Paradise Falls" // точный адрес неизвестен
  }
};
let customerCity = customer.details?.address?.city;

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

<h3 id="Использование_с_оператором">Использование с оператором ??</h3>

<p>Оператор {{JSxRef("Operators/Nullish_Coalescing_Operator", "??", '', 1)}} может использоваться после опциональной последовательности для установления значения по умолчанию:</p>

<pre>let customer = {
  name: "Carl",
  details: { age: 82 }
};
const customerCity = customer?.city ?? "Unknown city";
console.log(customerCity); // Unknown city</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/">Proposal for the "optional chaining" operator</a></td>
   <td>Stage 4</td>
   <td></td>
  </tr>
 </tbody>
</table>

<h2 id="Совместимость_с_браузерами">Совместимость с браузерами</h2>

<div>


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

<h2 id="Смотрите_также">Смотрите также</h2>

<ul>
 <li><a href="https://github.com/tc39/proposal-pipeline-operator">Github - Proposal-pipeline-operator</a></li>
 <li><a href="https://github.com/tc39/proposals">TC39 proposals</a></li>
 <li>{{JSxRef("Operators/Nullish_Coalescing_Operator", "Nullish Coalescing Operator", '', 1)}}</li>
</ul>