You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
옵셔널 체이닝(optional chaining) `?.`을 사용하면 프로퍼티가 없는 중첩 객체를 에러 없이 안전하게 접근할 수 있습니다.
8
7
9
8
## 옵셔널 체이닝이 필요한 이유
10
-
=======
11
-
The optional chaining `?.` is a safe way to access nested object properties, even if an intermediate property doesn't exist.
12
-
13
-
## The "non-existing property" problem
14
-
>>>>>>> upstream/master
15
9
16
10
이제 막 자바스크립트를 배우기 시작했다면 옵셔널 체이닝이 등장하게 된 배경 상황을 직접 겪어보지 않았을 겁니다. 몇 가지 사례를 재현하면서 왜 옵셔널 체이닝이 등장했는지 알아봅시다.
17
11
18
-
<<<<<<< HEAD
19
12
사용자가 여러 명 있는데 그중 몇 명은 주소 정보를 가지고 있지 않다고 가정해봅시다. 이럴 때 `user.address.street`를 사용해 주소 정보에 접근하면 에러가 발생할 수 있습니다.
20
13
21
14
```js run
22
15
let user = {}; // 주소 정보가 없는 사용자
23
-
=======
24
-
As an example, let's say we have `user` objects that hold the information about our users.
25
-
26
-
Most of our users have addresses in `user.address` property, with the street `user.address.street`, but some did not provide them.
27
-
28
-
In such case, when we attempt to get `user.address.street`, and the user happens to be without an address, we get an error:
29
-
30
-
```js run
31
-
let user = {}; // a user without "address" property
32
-
>>>>>>> upstream/master
33
16
34
17
alert(user.address.street); // TypeError: Cannot read property 'street' of undefined
35
18
```
36
19
37
-
<<<<<<< HEAD
20
+
이는 예상된 결과입니다. 자바스크립트는 이런 식으로 동작합니다. `user.address`가 `undefined`이므로 `user.address.street`를 가져오려는 시도는 에러를 발생시킵니다.
21
+
22
+
실제 개발 환경에서는 이런 상황에서 에러 대신 `undefined`를 반환받는 것이 더 나은 경우가 많습니다.
23
+
38
24
또 다른 사례론 브라우저에서 동작하는 코드를 개발할 때 발생할 수 있는 문제가 있습니다. 자바스크립트를 사용해 페이지에 존재하지 않는 요소에 접근해 요소의 정보를 가져오려 하면 문제가 발생하죠.
39
25
40
26
```js run
41
27
// querySelector(...) 호출 결과가 null인 경우 에러 발생
42
28
let html =document.querySelector('.my-element').innerHTML;
43
29
```
44
30
45
-
명세서에 `?.`이 추가되기 전엔 이런 문제들을 해결하기 위해 `&&` 연산자를 사용하곤 했습니다.
46
-
47
-
예시:
48
-
=======
49
-
That's the expected result. JavaScript works like this. As`user.address` is `undefined`, an attempt to get `user.address.street` fails with an error.
31
+
이 경우에도 요소가 존재하지 않으면 `null의``.innerHTML` 프로퍼티에 접근하려 했기 때문에 에러가 발생합니다. 요소가 없는 것이 정상적인 상황일 때도 있는데, 이럴 때는 에러를 피하고 그냥 `html = null`을 결과로 받아들이고 싶을 것입니다.
50
32
51
-
In many practical cases we'd prefer to get `undefined` instead of an error here (meaning "no street").
33
+
어떻게 하면 될까요?
52
34
53
-
...and another example. In Web development, we can get an object that corresponds to a web page element using a special method call, such as `document.querySelector('.elem')`, and it returns `null` when there's no such element.
35
+
가장 직관적인 해결책은 프로퍼티에 접근하기 전에 `if`문이나 조건부 연산자 `?`를 사용해 값을 확인하는 것입니다. 다음과 같이 말이죠.
54
36
55
-
```js run
56
-
// document.querySelector('.elem') is null if there's no element
57
-
let html = document.querySelector('.elem').innerHTML; // error if it's null
58
37
```
59
-
60
-
Once again, if the element doesn't exist, we'll get an error accessing `.innerHTML` property of`null`. Andin some cases, when the absence of the element is normal, we'd like to avoid the error and just accept `html = null` as the result.
61
-
62
-
How can we do this?
63
-
64
-
The obvious solution would be to check the value using `if` or the conditional operator `?`, before accessing its property, like this:
위 예시를 통해 우리는 `?.`은 `?.` '앞' 평가 대상에만 동작되고, 확장은 되지 않는다는 사실을 알 수 있습니다.
165
125
166
-
<<<<<<< HEAD
167
126
참고로 위 예시에서 사용된 `user?.`는 `user`가 `null`이나 `undefined`인 경우만 처리할 수 있습니다.
168
127
169
128
`user`가 `null`이나 `undefined`가 아니고 실제 값이 존재하는 경우엔 반드시 `user.address` 프로퍼티는 있어야 합니다. 그렇지 않으면 `user?.address.street`의 두 번째 점 연산자에서 에러가 발생합니다.
170
-
=======
171
-
E.g. in `user?.address.street.name` the `?.` allows `user` to safely be `null/undefined` (and returns `undefined` in that case), but that's only for `user`. Further properties are accessed in a regular way. If we want some of them to be optional, then we'll need to replace more `.` with `?.`.
172
-
>>>>>>> upstream/master
173
129
174
130
```warn header="옵셔널 체이닝을 남용하지 마세요."
175
131
`?.`는 존재하지 않아도 괜찮은 대상에만 사용해야 합니다.
176
132
177
-
<<<<<<<HEAD
178
133
사용자 주소를 다루는 위 예시에서 논리상 `user`는 반드시 있어야 하는데 `address`는 필수값이 아닙니다. 그러니 `user.address?.street`를 사용하는 것이 바람직합니다.
179
134
180
-
실수로 인해 `user`에 값을 할당하지 않았다면 바로 알아낼 수 있도록 해야 합니다. 그렇지 않으면 에러를 조기에 발견하지 못하고 디버깅이 어려워집니다.
181
-
=======
182
-
For example, if according to our code logic `user` object must exist, but `address` is optional, then we should write `user.address?.street`, but not `user?.address?.street`.
183
-
184
-
Then, if`user` happens to be undefined, we'll see a programming error about it and fix it. Otherwise, if we overuse `?.`, coding errors can be silenced where not appropriate, and become more difficult to debug.
185
-
>>>>>>> upstream/master
135
+
이렇게 하면 실수로 `user`가 `undefined`가 되었을 때 이를 알려주는 에러가 발생하므로 바로 확인하고 수정할 수 있습니다. 반대로 `?.`을 남용하면, 적절치 않은 상황에서도 에러가 조용히 무시되어 버리기 때문에 디버깅이 더욱 어려워집니다.
186
136
```
187
137
188
138
````warn header="`?.`앞의 변수는 꼭 선언되어 있어야 합니다."
@@ -192,43 +142,25 @@ Then, if `user` happens to be undefined, we'll see a programming error about it
192
142
// ReferenceError: user is not defined
193
143
user?.address;
194
144
```
195
-
<<<<<<< HEAD
196
145
`user?.anything`을 사용하려면 `let`이나 `const`, `var`를 사용해 `user`를 정의해야 하죠. 이렇게 옵셔널 체이닝은 선언이 완료된 변수를 대상으로만 동작합니다.
197
-
=======
198
-
The variable must be declared (e.g. `let/const/var user` or as a function parameter). The optional chaining works only for declared variables.
199
-
>>>>>>> upstream/master
200
146
````
201
147
202
148
## 단락 평가
203
149
204
150
`?.`는 왼쪽 평가대상에 값이 없으면 즉시 평가를 멈춥니다. 참고로 이런 평가 방법을 단락 평가(short-circuit)라고 부릅니다.
205
151
206
-
<<<<<<< HEAD
207
152
그렇기 때문에 함수 호출을 비롯한 `?.` 오른쪽에 있는 부가 동작은 `?.`의 평가가 멈췄을 때 더는 일어나지 않습니다.
208
-
=======
209
-
So, if there are any further function calls or operations to the right of `?.`, they won't be made.
210
-
211
-
For instance:
212
-
>>>>>>> upstream/master
213
153
214
154
```js run
215
155
let user = null;
216
156
let x = 0;
217
157
218
-
<<<<<<< HEAD
219
158
user?.sayHi(x++); // 아무 일도 일어나지 않습니다.
220
-
=======
221
-
user?.sayHi(x++); // no "user", so the execution doesn't reach sayHi call and x++
222
-
>>>>>>> upstream/master
223
159
224
160
alert(x); // 0, x는 증가하지 않습니다.
225
161
```
226
162
227
-
<<<<<<<HEAD
228
163
## ?.()와 ?.[]
229
-
=======
230
-
## Other variants:?.(), ?.[]
231
-
>>>>>>> upstream/master
232
164
233
165
`?.`은 연산자가 아닙니다. `?.`은 함수나 대괄호와 함께 동작하는 특별한 문법 구조체(syntax construct)입니다.
234
166
@@ -246,7 +178,6 @@ let userAdmin = {
246
178
let userGuest = {};
247
179
248
180
*!*
249
-
<<<<<<< HEAD
250
181
user1.admin?.(); // 관리자 계정입니다.
251
182
user2.admin?.();
252
183
*/!*
@@ -255,19 +186,6 @@ user2.admin?.();
255
186
두 상황 모두에서 user 객체는 존재하기 때문에 `admin` 프로퍼티는 `.`만 사용해 접근했습니다.
256
187
257
188
그리고 난 후 `?.()`를 사용해 `admin`의 존재 여부를 확인했습니다. `user1`엔 `admin`이 정의되어 있기 때문에 메서드가 제대로 호출되었습니다. 반면 `user2`엔 `admin`이 정의되어 있지 않았음에도 불구하고 메서드를 호출하면 에러 없이 그냥 평가가 멈추는 것을 확인할 수 있습니다.
258
-
=======
259
-
userAdmin.admin?.(); // I am admin
260
-
*/!*
261
-
262
-
*!*
263
-
userGuest.admin?.(); // nothing happens (no such method)
264
-
*/!*
265
-
```
266
-
267
-
Here, in both lines we first use the dot (`userAdmin.admin`) to get `admin` property, because we assume that the `user` object exists, so it's safe read from it.
268
-
269
-
Then `?.()` checks the left part: if the `admin` function exists, then it runs (that's so for `userAdmin`). Otherwise (for `userGuest`) the evaluation stops without errors.
270
-
>>>>>>> upstream/master
271
189
272
190
`.`대신 대괄호 `[]`를 사용해 객체 프로퍼티에 접근하는 경우엔 `?.[]`를 사용할 수도 있습니다. 위 예시와 마찬가지로 `?.[]`를 사용하면 객체 존재 여부가 확실치 않은 경우에도 안전하게 프로퍼티를 읽을 수 있습니다.
여러 예시를 통해 살펴보았듯이 옵셔널 체이닝 문법은 꽤 직관적이고 사용하기도 쉽습니다. `?.` 왼쪽 평가 대상이 `null`이나 `undefined`인지 확인하고 `null`이나 `undefined`가 아니라면 평가를 계속 진행합니다.
342
233
343
234
`?.`를 계속 연결해서 체인을 만들면 중첩 프로퍼티들에 안전하게 접근할 수 있습니다.
344
235
345
-
<<<<<<< HEAD
346
236
`?.`은 `?.`왼쪽 평가대상이 없어도 괜찮은 경우에만 선택적으로 사용해야 합니다.
347
237
348
238
꼭 있어야 하는 값인데 없는 경우에 `?.`을 사용하면 프로그래밍 에러를 쉽게 찾을 수 없으므로 이런 상황을 만들지 말도록 합시다.
349
-
=======
350
-
Still, we should apply `?.` carefully, only where it's acceptable, according to our code logic, that the left part doesn't exist. So that it won't hide programming errors from us, if they occur.
0 commit comments