Skip to content

Commit 4f2ad94

Browse files
committed
minor fixes
1 parent 238c5c3 commit 4f2ad94

File tree

1 file changed

+30
-15
lines changed
  • 1-js/04-object-basics/07-optional-chaining

1 file changed

+30
-15
lines changed

1-js/04-object-basics/07-optional-chaining/article.md

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ alert(user.address.street); // Ошибка!
3232
let html = document.querySelector('.elem').innerHTML; // ошибка, если он равен null
3333
```
3434

35-
Ещё раз, если элемент не существует, мы получим сообщение об ошибке доступа к `.innerHTML` со значением `null`. И в некоторых случаях, когда отсутствие элемента является нормальным, мы хотели бы избежать ошибки и просто принять `html = null` в качестве результата.
35+
Ещё раз, если элемент не существует, мы получим сообщение об ошибке доступа к свойству `.innerHTML` у `null`. И в некоторых случаях, когда отсутствие элемента является нормальным, мы хотели бы избежать ошибки и просто принять `html = null` в качестве результата.
3636

3737
Как мы можем это сделать?
3838

@@ -44,9 +44,19 @@ let user = {};
4444
alert(user.address ? user.address.street : undefined);
4545
```
4646

47-
Это работает, тут нет ошибки... Но это довольно неэлегантно. Как вы можете видеть, `"user.address"` появляется в коде дважды. Для более глубоко вложенных свойств это становится проблемой, поскольку потребуется больше повторений.
47+
Это работает, тут нет ошибки... Но это довольно неэлегантно. Как вы можете видеть, `"user.address"` появляется в коде дважды.
4848

49-
К примеру, давайте попробуем получить `user.address.street.name`.
49+
Вот как то же самое выглядело бы для `document.querySelector`:
50+
51+
```js run
52+
let html = document.querySelector('.elem') ? document.querySelector('.elem').innerHTML : null;
53+
```
54+
55+
Как видно, поиск элемента `document.querySelector('.elem')` здесь вызывается дважды, что не очень хорошо.
56+
57+
Для более глубоко вложенных свойств это ещё менее красиво, поскольку потребуется больше повторений.
58+
59+
К примеру, давайте аналогично вычислим `user.address.street.name`.
5060

5161
Нам нужно проверить как `user.address`, так и `user.address.street`:
5262

@@ -58,7 +68,7 @@ alert(user.address ? user.address.street ? user.address.street.name : null : nul
5868

5969
Это просто ужасно, у кого-то могут даже возникнуть проблемы с пониманием такого кода.
6070

61-
На самом деле это не большая проблема, так как есть лучший способ написать это, используя оператор `&&`:
71+
Есть немного лучший способ написать это, используя оператор `&&`:
6272

6373
```js run
6474
let user = {}; // пользователь без адреса
@@ -70,7 +80,7 @@ alert( user.address && user.address.street && user.address.street.name ); // und
7080

7181
Как вы можете видеть, имена свойств по-прежнему дублируются в коде. Например, в приведённом выше коде `user.address` появляется три раза.
7282

73-
Вот почему в язык была добавлена опциональная цепочка `?.`. Чтобы решить эту проблему раз и навсегда!
83+
Вот почему в язык была добавлена опциональная цепочка `?.`. Чтобы решить эту проблему - раз и навсегда!
7484

7585
## Опциональная цепочка
7686

@@ -92,6 +102,12 @@ alert( user?.address?.street ); // undefined (без ошибки)
92102
93103
Код лаконичный и понятный, в нем вообще нет дублирования.
94104
105+
А вот пример с `document.querySelector`:
106+
107+
```js run
108+
let html = document.querySelector('.elem')?.innerHTML; // будет null, если элемента нет
109+
```
110+
95111
Считывание адреса с помощью `user?.address` работает, даже если объект `user` не существует:
96112
97113
```js run
@@ -103,12 +119,12 @@ alert( user?.address.street ); // undefined
103119
104120
Обратите внимание: синтаксис `?.` делает необязательным значение перед ним, но не какое-либо последующее.
105121
106-
Так например, в `user?.address.street.name` `?.` позволяет `user` безопасно быть `null/undefined` (и в этом случае возвращает `undefined`), но это только для `user`. Доступ к последующим свойствам осуществляется обычным способом. Если мы хотим, чтобы некоторые из них были необязательными, тогда нам нужно будет заменить больше `.` на `?.`.
122+
Так например, в записи `user?.address.street.name` `?.` позволяет `user` безопасно быть `null/undefined` (и в этом случае возвращает `undefined`), но это так только для `user`. Доступ к последующим свойствам осуществляется обычным способом. Если мы хотим, чтобы некоторые из них были необязательными, тогда нам нужно будет заменить больше `.` на `?.`.
107123
108124
```warn header="Не злоупотребляйте опциональной цепочкой"
109125
Нам следует использовать `?.` только там, где нормально, что чего-то не существует.
110126

111-
К примеру, если, в соответствии с нашей логикой кода, объект `user` должен существовать, но `address` является необязательным, то нам следует писать `user.address?.street`, но не `user?.address?.street`.
127+
К примеру, если, в соответствии с логикой нашего кода, объект `user` должен существовать, но `address` является необязательным, то нам следует писать `user.address?.street`, но не `user?.address?.street`.
112128

113129
В этом случае, если вдруг `user` окажется `undefined`, мы увидим программную ошибку по этому поводу и исправим её. В противном случае, если слишком часто использовать `?.`, ошибки могут замалчиваться там, где это неуместно, и их будет сложнее отлаживать.
114130
```
@@ -151,22 +167,22 @@ alert(x); // 0, значение не увеличилось
151167
```js run
152168
let userAdmin = {
153169
admin() {
154-
alert("I am admin");
170+
alert("Я админ");
155171
}
156172
};
157173
158174
let userGuest = {};
159175
160176
*!*
161-
userAdmin.admin?.(); // I am admin
177+
userAdmin.admin?.(); // Я админ
162178
*/!*
163179
164180
*!*
165-
userGuest.admin?.(); // ничего (такого метода нет)
181+
userGuest.admin?.(); // ничего не произойдет (такого метода нет)
166182
*/!*
167183
```
168184

169-
Здесь в обеих строках мы сначала используем точку (`userAdmin.admin`), чтобы получить свойство `admin`, потому что мы предполагаем, что объект user существует, так что читать из него безопасно.
185+
Здесь в обеих строках мы сначала используем точку (`userAdmin.admin`), чтобы получить свойство `admin`, потому что мы предполагаем, что объект `user` существует, так что читать из него безопасно.
170186

171187
Затем `?.()` проверяет левую часть: если функция `admin` существует, то она запускается (это так для `userAdmin`). В противном случае (для `userGuest`) вычисление остановится без ошибок.
172188

@@ -179,7 +195,7 @@ let user1 = {
179195
firstName: "John"
180196
};
181197
182-
let user2 = null;
198+
let user2 = null;
183199
184200
alert( user1?.[key] ); // John
185201
alert( user2?.[key] ); // undefined
@@ -199,10 +215,9 @@ delete user?.name; // удаляет user.name если пользователь
199215
let user = null;
200216
201217
user?.name = "John"; // Ошибка, не работает
202-
// потому что вычисляется как undefined = "John"
218+
// то же самое что написать undefined = "John"
203219
```
204220

205-
Она недостаточно "умна" для этого.
206221
````
207222

208223
## Итого
@@ -217,4 +232,4 @@ user?.name = "John"; // Ошибка, не работает
217232

218233
Цепочка `?.` позволяет безопасно получать доступ к вложенным свойствам.
219234

220-
Тем не менее, мы должны использовать `?.` осторожно, только там, где допустимо, что левая часть не существует. И чтобы он не скрывал от нас ошибки программирования, если они возникнут.
235+
Тем не менее, мы должны использовать `?.` осторожно, только там, где по логике кода допустимо, что левая часть не существует. Чтобы он не скрывал от нас ошибки программирования, если они возникнут.

0 commit comments

Comments
 (0)