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
`obj1 + obj2` 처럼 객체끼리 더하는 연산을 하거나, `obj1 - obj2` 처럼 객체끼리 빼는 연산을 하면 어떤 일이 일어날까요? `alert(obj)`로 객체를 출력할 때는 무슨 일이 발생할까요?
5
5
6
-
<<<<<<< HEAD
7
6
이 모든 경우에 자동 형 변환이 일어납니다. 객체는 원시값으로 변환되고, 그 후 의도한 연산이 수행됩니다.
8
-
=======
9
-
JavaScript doesn't allow you to customize how operators work on objects. Unlike some other programming languages, such as Ruby or C++, we can't implement a special object method to handle addition (or other operators).
10
7
11
-
In case of such operations, objects are auto-converted to primitives, and then the operation is carried out over these primitives and results in a primitive value.
8
+
Ruby나 C++ 같은 다른 프로그래밍 언어와 달리, 덧셈(이나 다른 연산)을 처리하기 위한 특별한 객체 메서드를 구현할 수 없죠.
12
9
13
-
That's an important limitation: the result of `obj1 + obj2` (or another math operation) can't be another object!
10
+
객체에 이런 연산을 수행하면 객체는 원시값으로 자동 변환되고, 이후 이 원시값들을 대상으로 연산이 수행되어 최종적으로 원시값이 반환됩니다.
14
11
15
-
E.g. we can't make objects representing vectors or matrices (or achievements or whatever), add them and expect a "summed" object as the result. Such architectural feats are automatically "off the board".
12
+
이는 아주 중요한 제한 사항입니다. `obj1 + obj2` (또는 다른 수학 연산)의 결과는 또 다른 객체가 될 수 없습니다!
16
13
17
-
So, because we can't technically do much here, there's no maths with objects in real projects. When it happens, with rare exceptions, it's because of a coding mistake.
14
+
예를 들어, 벡터나 행렬(또는 게임의 성과 등)을 나타내는 객체를 만들고, 이를 더해서 '합산된' 객체를 결과로 기대할 수는 없습니다. 이러한 구조적 시도는 애초에 불가능합니다.
18
15
19
-
In this chapter we'll cover how an object converts to primitive and how to customize it.
16
+
이처럼 기술적인 제약이 있기 때문에 실제 프로젝트에서 객체를 대상으로 수학 연산을 하는 경우는 없습니다. 극히 예외적인 상황을 제외하면, 이런 연산이 발생했다는 것은 곧 코딩 실수가 있었음을 의미합니다.
20
17
21
-
We have two purposes:
18
+
이번 챕터에서는 객체가 어떻게 원시값으로 변환되는지, 그리고 이 변환을 어떻게 커스터마이징할 수 있는지 알아보겠습니다.
22
19
23
-
1. It will allow us to understand what's going on in case of coding mistakes, when such an operation happened accidentally.
24
-
2. There are exceptions, where such operations are possible and look good. E.g. subtracting or comparing dates (`Date` objects). We'll come across them later.
20
+
우리가 이를 배우는 목적은 두 가지입니다.
21
+
22
+
1. 코딩 실수로 인해 의도치 않게 객체 연산이 발생했을 때, 내부적으로 어떤 일이 벌어지는지 이해하기 위해서입니다.
23
+
24
+
2. 이런 연산이 가능하며 심지어 유용하게 쓰이는 예외적인 상황이 있기 때문입니다. 날짜(`Date` 객체)를 빼거나 비교하는 경우가 대표적인데, 이에 대해서는 나중에 다루겠습니다.
25
25
26
-
## Conversion rules
27
-
>>>>>>> upstream/master
28
26
29
27
<info:type-conversions> 챕터에선 객체의 형 변환은 다루지 않았습니다. 원시형 자료가 어떻게 문자, 숫자, 논리형으로 변환되는지만 알아보았죠. 이젠 메서드와 심볼에 대한 지식을 갖추었으니 본격적으로 이 공백을 메꿔봅시다.
30
28
31
-
<<<<<<< HEAD
32
29
1. 객체는 논리 평가 시 `true`를 반환합니다. 단 하나의 예외도 없죠. 따라서 객체는 숫자형이나 문자형으로만 형 변환이 일어난다고 생각하시면 됩니다.
33
30
2. 숫자형으로의 형 변환은 객체끼리 빼는 연산을 할 때나 수학 관련 함수를 적용할 때 일어납니다. 객체 `Date`끼리 차감하면(`date1 - date2`) 두 날짜의 시간 차이가 반환됩니다. `Date`에 대해선 <info:date>에서 다룰 예정입니다.
34
31
3. 문자형으로의 형 변환은 대개 `alert(obj)`같이 객체를 출력하려고 할 때 일어납니다.
35
-
=======
36
-
1. There's no conversion to boolean. All objects are `true` in a boolean context, as simple as that. There exist only numeric and string conversions.
37
-
2. The numeric conversion happens when we subtract objects or apply mathematical functions. For instance, `Date` objects (to be covered in the chapter <info:date>) can be subtracted, and the result of `date1 - date2` is the time difference between two dates.
38
-
3. As for the string conversion -- it usually happens when we output an object with `alert(obj)` and in similar contexts.
39
-
>>>>>>> upstream/master
40
32
41
33
We can implement string and numeric conversion by ourselves, using special object methods.
42
34
43
-
<<<<<<< HEAD
44
35
특수 객체 메서드를 사용하면 숫자형이나 문자형으로의 형 변환을 원하는 대로 조절할 수 있습니다.
45
36
46
37
객체 형 변환은 세 종류로 구분되는데, 'hint'라 불리는 값이 구분 기준이 됩니다. 'hint'가 무엇인지는 [명세서](https://tc39.github.io/ecma262/#sec-toprimitive)에 자세히 설명되어 있는데, '목표로 하는 자료형' 정도로 이해하시면 될 것 같습니다.
47
-
=======
48
-
Now let's get into technical details, because it's the only way to cover the topic in-depth.
49
-
50
-
## Hints
51
-
52
-
How does JavaScript decide which conversion to apply?
53
-
54
-
There are three variants of type conversion, that happen in various situations. They're called "hints", as described in the [specification](https://tc39.github.io/ecma262/#sec-toprimitive):
55
-
>>>>>>> upstream/master
56
38
57
39
`"string"`
58
40
: `alert` 함수같이 문자열을 기대하는 연산을 수행할 때는(객체-문자형 변환), hint가 `string`이 됩니다.
@@ -85,11 +67,7 @@ There are three variants of type conversion, that happen in various situations.
85
67
`"default"`
86
68
: 연산자가 기대하는 자료형이 '확실치 않을 때' hint는 `default`가 됩니다. 아주 드물게 발생합니다.
87
69
88
-
<<<<<<< HEAD
89
70
이항 덧셈 연산자 `+`는 피연산자의 자료형에 따라 문자열을 합치는 연산을 할 수도 있고 숫자를 더해주는 연산을 할 수도 있습니다. 따라서 `+`의 인수가 객체일 때는 hint가 `default`가 됩니다.
90
-
=======
91
-
For instance, binary plus `+` can work both with strings (concatenates them) and numbers (adds them). So if a binary plus gets an object as an argument, it uses the `"default"` hint to convert it.
92
-
>>>>>>> upstream/master
93
71
94
72
동등 연산자 `==`를 사용해 객체-문자형, 객체-숫자형, 객체-심볼형끼리 비교할 때도, 객체를 어떤 자료형으로 바꿔야 할지 확신이 안 서므로 hint는 default가 됩니다.
95
73
@@ -103,61 +81,33 @@ There are three variants of type conversion, that happen in various situations.
103
81
104
82
크고 작음을 비교할 때 쓰이는 연산자 `<`, `>` 역시 피연산자에 문자형과 숫자형 둘 다를 허용하는데, 이 연산자들은 hint를 'number'로 고정합니다. hint가 'default'가 되는 일이 없죠. 이는 하위 호환성 때문에 정해진 규칙입니다.
105
83
106
-
<<<<<<< HEAD
107
84
실제 일을 할 때는 이런 사항을 모두 외울 필요는 없습니다. `Date` 객체를 제외한 모든 내장 객체는 hint가 `"default"`인 경우와 `"number"`인 경우를 동일하게 처리하기 때문입니다. 우리도 커스텀 객체를 만들 땐 이런 규칙을 따르면 됩니다.
108
85
109
86
```smart header="`\"boolean\"` hint는 없습니다."
110
87
hint는 총 세 가지입니다. 아주 간단하죠.
111
88
112
89
'boolean' hint는 존재하지 않습니다. 모든 객체는 그냥 `true`로 평가됩니다. 게다가 우리도 내장 객체에 사용되는 규칙처럼 `"default"`와 `"number"`를 동일하게 처리하면, 결국엔 두 종류의 형 변환(객체-문자형, 객체-숫자형)만 남게 됩니다.
113
90
```
114
-
=======
115
-
In practice though, things are a bit simpler.
116
-
117
-
All built-in objects except for one case (`Date` object, we'll learn it later) implement `"default"` conversion the same way as `"number"`. And we probably should do the same.
118
-
119
-
Still, it's important to know about all 3 hints, soon we'll see why.
120
-
>>>>>>> upstream/master
121
91
122
92
**자바스크립트는 형 변환이 필요할 때, 아래와 같은 알고리즘에 따라 원하는 메서드를 찾고 호출합니다.**
123
93
124
-
<<<<<<< HEAD
125
94
1. 객체에 `obj[Symbol.toPrimitive](hint)`메서드가 있는지 찾고, 있다면 메서드를 호출합니다. `Symbol.toPrimitive`는 시스템 심볼로, 심볼형 키로 사용됩니다.
1. Call `obj[Symbol.toPrimitive](hint)` - the method with the symbolic key `Symbol.toPrimitive` (system symbol), if such method exists,
132
-
2. Otherwise if hint is `"string"`
133
-
- try calling `obj.toString()` or `obj.valueOf()`, whatever exists.
134
-
3. Otherwise if hint is `"number"` or `"default"`
135
-
- try calling `obj.valueOf()` or `obj.toString()`, whatever exists.
136
-
>>>>>>> upstream/master
137
99
138
100
## Symbol.toPrimitive
139
101
140
102
첫 번째 메서드부터 살펴봅시다. 자바스크립트엔 `Symbol.toPrimitive`라는 내장 심볼이 존재하는데, 이 심볼은 아래와 같이 목표로 하는 자료형(hint)을 명명하는 데 사용됩니다.
141
103
```js
142
104
obj[Symbol.toPrimitive] = function(hint) {
143
-
<<<<<<< HEAD
144
105
// 반드시 원시값을 반환해야 합니다.
145
106
// hint는 "string", "number", "default" 중 하나가 될 수 있습니다.
146
107
};
147
108
```
148
109
149
110
실제 돌아가는 예시를 살펴보는 게 좋을 것 같네요. `user` 객체에 객체-원시형 변환 메서드 `obj[Symbol.toPrimitive](hint)`를 구현해보겠습니다.
150
-
=======
151
-
// here goes the code to convert this object to a primitive
152
-
// it must return a primitive value
153
-
// hint = one of "string", "number", "default"
154
-
};
155
-
```
156
-
157
-
If the method `Symbol.toPrimitive` exists, it's used for all hints, and no more methods are needed.
158
-
159
-
For instance, here `user` object implements it:
160
-
>>>>>>> upstream/master
161
111
162
112
```js run
163
113
let user = {
@@ -176,16 +126,11 @@ alert(+user); // hint: number -> 1000
176
126
alert(user +500); // hint: default -> 1500
177
127
```
178
128
179
-
<<<<<<< HEAD
180
129
이렇게 메서드를 구현해 놓으면 `user`는 hint에 따라 (자기 자신을 설명해주는) 문자열로 변환되기도 하고 (가지고 있는 돈의 액수를 나타내는) 숫자로 변환되기도 합니다. `user[Symbol.toPrimitive]`를 사용하면 메서드 하나로 모든 종류의 형 변환을 다룰 수 있습니다.
181
130
182
-
=======
183
-
As we can see from the code, `user` becomes a self-descriptive string or a money amount, depending on the conversion. The single method `user[Symbol.toPrimitive]` handles all conversion cases.
184
-
>>>>>>> upstream/master
185
131
186
132
## toString과 valueOf
187
133
188
-
<<<<<<< HEAD
189
134
`toString`과 `valueOf`는 심볼이 생기기 이전부터 존재해 왔던 '평범한' 메서드입니다. 이 메서드를 이용하면 '구식'이긴 하지만 형 변환을 직접 구현할 수 있습니다.
190
135
191
136
객체에 `Symbol.toPrimitive`가 없으면 자바스크립트는 아래 규칙에 따라 `toString`이나 `valueOf`를 호출합니다.
@@ -194,16 +139,6 @@ As we can see from the code, `user` becomes a self-descriptive string or a money
194
139
- 그 외: `valueOf -> toString` 순
195
140
196
141
이 메서드들은 반드시 원시값을 반환해야합니다. `toString`이나 `valueOf`가 객체를 반환하면 그 결과는 무시됩니다. 마치 메서드가 처음부터 없었던 것처럼 되어버리죠.
197
-
=======
198
-
If there's no `Symbol.toPrimitive` then JavaScript tries to find methods `toString` and `valueOf`:
199
-
200
-
- For the `"string"` hint: call `toString` method, and if it doesn't exist or if it returns an object instead of a primitive value, then call `valueOf` (so `toString` has the priority for string conversions).
201
-
- For other hints: call `valueOf`, and if it doesn't exist or if it returns an object instead of a primitive value, then call `toString` (so `valueOf` has the priority for maths).
202
-
203
-
Methods `toString` and `valueOf` come from ancient times. They are not symbols (symbols did not exist that long ago), but rather "regular" string-named methods. They provide an alternative "old-style" way to implement the conversion.
204
-
205
-
These methods must return a primitive value. If `toString` or `valueOf` returns an object, then it's ignored (same as if there were no method).
206
-
>>>>>>> upstream/master
207
142
208
143
일반 객체는 기본적으로 `toString`과 `valueOf`에 적용되는 다음 규칙을 따릅니다.
이런 이유 때문에 `alert`에 객체를 넘기면 `[object Object]`가 출력되는 것입니다.
223
158
224
-
<<<<<<< HEAD
225
159
여기서 `valueOf`는 튜토리얼의 완성도를 높이고 헷갈리는 것을 줄여주려고 언급했습니다. 앞서 본 바와 같이 `valueOf`는 객체 자신을 반환하기 때문에 그 결과가 무시됩니다. 왜 그런거냐고 이유를 묻지는 말아주세요. 그냥 역사적인 이유때문입니다. 우리는 그냥 이 메서드가 존재하지 않는다고 생각하면 됩니다.
226
160
227
161
이제 직접 이 메서드들을 사용한 예시를 구현해봅시다.
228
-
=======
229
-
The default `valueOf` is mentioned here only for the sake of completeness, to avoid any confusion. As you can see, it returns the object itself, and so is ignored. Don't ask me why, that's for historical reasons. So we can assume it doesn't exist.
230
-
231
-
Let's implement these methods to customize the conversion.
232
-
>>>>>>> upstream/master
233
162
234
163
아래 `user`는 `toString`과 `valueOf`를 조합해 만들었는데, `Symbol.toPrimitive`를 사용한 위쪽 예시와 동일하게 동작합니다.
alert(obj +2); // "22" ("2" + 2), conversion to primitive returned a string => concatenation
348
-
>>>>>>> upstream/master
349
259
```
350
260
351
261
## 요약
352
262
353
263
원시값을 기대하는 내장 함수나 연산자를 사용할 때 객체-원시형으로의 형 변환이 자동으로 일어납니다.
354
264
355
-
<<<<<<< HEAD
356
265
객체-원시형으로의 형 변환은 hint를 기준으로 세 종류로 구분할 수 있습니다.
357
266
-`"string"` (`alert` 같이 문자열을 필요로 하는 연산)
358
267
-`"number"` (수학 연산)
359
268
-`"default"` (드물게 발생함)
360
269
361
270
연산자별로 어떤 hint가 적용되는지는 명세서에서 찾아볼 수 있습니다. 연산자가 기대하는 피연산자를 '확신할 수 없을 때'에는 hint가 `"default"`가 됩니다. 이런 경우는 아주 드물게 발생합니다. 내장 객체는 대개 hint가 `"default"`일 때와 `"number"`일 때를 동일하게 처리합니다. 따라서 실무에선 hint가 `"default"`인 경우와 `"number"`인 경우를 합쳐서 처리하는 경우가 많습니다.
362
-
=======
363
-
There are 3 types (hints) of it:
364
-
-`"string"` (for `alert` and other operations that need a string)
365
-
-`"number"` (for maths)
366
-
-`"default"` (few operators, usually objects implement it the same way as `"number"`)
367
-
368
-
The specification describes explicitly which operator uses which hint.
369
-
>>>>>>> upstream/master
370
271
371
272
객체-원시형 변환엔 다음 알고리즘이 적용됩니다.
372
273
373
-
<<<<<<< HEAD
374
274
1. 객체에 `obj[Symbol.toPrimitive](hint)`메서드가 있는지 찾고, 있다면 호출합니다.
375
275
2. 1에 해당하지 않고 hint가 `"string"`이라면,
376
276
-`obj.toString()`이나 `obj.valueOf()`를 호출합니다.
377
277
3. 1과 2에 해당하지 않고, hint가 `"number"`나 `"default"`라면
378
278
-`obj.valueOf()`나 `obj.toString()`을 호출합니다.
379
279
380
280
`obj.toString()`만 사용해도 '모든 변환'을 다 다룰 수 있기 때문에, 실무에선 `obj.toString()`만 구현해도 충분한 경우가 많습니다. 반환 값도 '사람이 읽고 이해할 수 있는' 형식이기 때문에 실용성 측면에서 다른 메서드에 뒤처지지 않습니다. `obj.toString()`은 로깅이나 디버깅 목적으로도 자주 사용됩니다.
381
-
=======
382
-
1. Call `obj[Symbol.toPrimitive](hint)` if the method exists,
383
-
2. Otherwise if hint is `"string"`
384
-
- try calling `obj.toString()` or `obj.valueOf()`, whatever exists.
385
-
3. Otherwise if hint is `"number"` or `"default"`
386
-
- try calling `obj.valueOf()` or `obj.toString()`, whatever exists.
387
-
388
-
All these methods must return a primitive to work (if defined).
389
-
390
-
In practice, it's often enough to implement only `obj.toString()` as a "catch-all" method for string conversions that should return a "human-readable" representation of an object, for logging or debugging purposes.
0 commit comments