Skip to content

Commit 103871a

Browse files
committed
[객체를 원시형으로 변환] 충돌 해결 (본문)
1 parent 77e23f1 commit 103871a

1 file changed

Lines changed: 16 additions & 127 deletions

File tree

  • 1-js/04-object-basics/09-object-toprimitive

1-js/04-object-basics/09-object-toprimitive/article.md

Lines changed: 16 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -3,56 +3,38 @@
33

44
`obj1 + obj2` 처럼 객체끼리 더하는 연산을 하거나, `obj1 - obj2` 처럼 객체끼리 빼는 연산을 하면 어떤 일이 일어날까요? `alert(obj)`로 객체를 출력할 때는 무슨 일이 발생할까요?
55

6-
<<<<<<< HEAD
76
이 모든 경우에 자동 형 변환이 일어납니다. 객체는 원시값으로 변환되고, 그 후 의도한 연산이 수행됩니다.
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).
107

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++ 같은 다른 프로그래밍 언어와 달리, 덧셈(이나 다른 연산)을 처리하기 위한 특별한 객체 메서드를 구현할 수 없죠.
129

13-
That's an important limitation: the result of `obj1 + obj2` (or another math operation) can't be another object!
10+
객체에 이런 연산을 수행하면 객체는 원시값으로 자동 변환되고, 이후 이 원시값들을 대상으로 연산이 수행되어 최종적으로 원시값이 반환됩니다.
1411

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` (또는 다른 수학 연산)의 결과는 또 다른 객체가 될 수 없습니다!
1613

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+
예를 들어, 벡터나 행렬(또는 게임의 성과 등)을 나타내는 객체를 만들고, 이를 더해서 '합산된' 객체를 결과로 기대할 수는 없습니다. 이러한 구조적 시도는 애초에 불가능합니다.
1815

19-
In this chapter we'll cover how an object converts to primitive and how to customize it.
16+
이처럼 기술적인 제약이 있기 때문에 실제 프로젝트에서 객체를 대상으로 수학 연산을 하는 경우는 없습니다. 극히 예외적인 상황을 제외하면, 이런 연산이 발생했다는 것은 곧 코딩 실수가 있었음을 의미합니다.
2017

21-
We have two purposes:
18+
이번 챕터에서는 객체가 어떻게 원시값으로 변환되는지, 그리고 이 변환을 어떻게 커스터마이징할 수 있는지 알아보겠습니다.
2219

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` 객체)를 빼거나 비교하는 경우가 대표적인데, 이에 대해서는 나중에 다루겠습니다.
2525

26-
## Conversion rules
27-
>>>>>>> upstream/master
2826

2927
<info:type-conversions> 챕터에선 객체의 형 변환은 다루지 않았습니다. 원시형 자료가 어떻게 문자, 숫자, 논리형으로 변환되는지만 알아보았죠. 이젠 메서드와 심볼에 대한 지식을 갖추었으니 본격적으로 이 공백을 메꿔봅시다.
3028

31-
<<<<<<< HEAD
3229
1. 객체는 논리 평가 시 `true`를 반환합니다. 단 하나의 예외도 없죠. 따라서 객체는 숫자형이나 문자형으로만 형 변환이 일어난다고 생각하시면 됩니다.
3330
2. 숫자형으로의 형 변환은 객체끼리 빼는 연산을 할 때나 수학 관련 함수를 적용할 때 일어납니다. 객체 `Date`끼리 차감하면(`date1 - date2`) 두 날짜의 시간 차이가 반환됩니다. `Date`에 대해선 <info:date>에서 다룰 예정입니다.
3431
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
4032

4133
We can implement string and numeric conversion by ourselves, using special object methods.
4234

43-
<<<<<<< HEAD
4435
특수 객체 메서드를 사용하면 숫자형이나 문자형으로의 형 변환을 원하는 대로 조절할 수 있습니다.
4536

4637
객체 형 변환은 세 종류로 구분되는데, '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
5638

5739
`"string"`
5840
: `alert` 함수같이 문자열을 기대하는 연산을 수행할 때는(객체-문자형 변환), hint가 `string`이 됩니다.
@@ -85,11 +67,7 @@ There are three variants of type conversion, that happen in various situations.
8567
`"default"`
8668
: 연산자가 기대하는 자료형이 '확실치 않을 때' hint는 `default`가 됩니다. 아주 드물게 발생합니다.
8769

88-
<<<<<<< HEAD
8970
이항 덧셈 연산자 `+`는 피연산자의 자료형에 따라 문자열을 합치는 연산을 할 수도 있고 숫자를 더해주는 연산을 할 수도 있습니다. 따라서 `+`의 인수가 객체일 때는 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
9371

9472
동등 연산자 `==`를 사용해 객체-문자형, 객체-숫자형, 객체-심볼형끼리 비교할 때도, 객체를 어떤 자료형으로 바꿔야 할지 확신이 안 서므로 hint는 default가 됩니다.
9573

@@ -103,61 +81,33 @@ There are three variants of type conversion, that happen in various situations.
10381

10482
크고 작음을 비교할 때 쓰이는 연산자 `<`, `>` 역시 피연산자에 문자형과 숫자형 둘 다를 허용하는데, 이 연산자들은 hint를 'number'로 고정합니다. hint가 'default'가 되는 일이 없죠. 이는 하위 호환성 때문에 정해진 규칙입니다.
10583

106-
<<<<<<< HEAD
10784
실제 일을 할 때는 이런 사항을 모두 외울 필요는 없습니다. `Date` 객체를 제외한 모든 내장 객체는 hint가 `"default"`인 경우와 `"number"`인 경우를 동일하게 처리하기 때문입니다. 우리도 커스텀 객체를 만들 땐 이런 규칙을 따르면 됩니다.
10885

10986
```smart header="`\"boolean\"` hint는 없습니다."
11087
hint는 총 세 가지입니다. 아주 간단하죠.
11188

11289
'boolean' hint는 존재하지 않습니다. 모든 객체는 그냥 `true`로 평가됩니다. 게다가 우리도 내장 객체에 사용되는 규칙처럼 `"default"``"number"`를 동일하게 처리하면, 결국엔 두 종류의 형 변환(객체-문자형, 객체-숫자형)만 남게 됩니다.
11390
```
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
12191
12292
**자바스크립트는 형 변환이 필요할 때, 아래와 같은 알고리즘에 따라 원하는 메서드를 찾고 호출합니다.**
12393
124-
<<<<<<< HEAD
12594
1. 객체에 `obj[Symbol.toPrimitive](hint)`메서드가 있는지 찾고, 있다면 메서드를 호출합니다. `Symbol.toPrimitive`는 시스템 심볼로, 심볼형 키로 사용됩니다.
12695
2. 1에 해당하지 않고 hint가 `"string"`이라면,
12796
- `obj.toString()`이나 `obj.valueOf()`를 호출합니다(존재하는 메서드만 실행됨).
12897
3. 1과 2에 해당하지 않고, hint가 `"number"`나 `"default"`라면
12998
- `obj.valueOf()`나 `obj.toString()`을 호출합니다(존재하는 메서드만 실행됨).
130-
=======
131-
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
13799
138100
## Symbol.toPrimitive
139101
140102
첫 번째 메서드부터 살펴봅시다. 자바스크립트엔 `Symbol.toPrimitive`라는 내장 심볼이 존재하는데, 이 심볼은 아래와 같이 목표로 하는 자료형(hint)을 명명하는 데 사용됩니다.
141103
```js
142104
obj[Symbol.toPrimitive] = function(hint) {
143-
<<<<<<< HEAD
144105
// 반드시 원시값을 반환해야 합니다.
145106
// hint는 "string", "number", "default" 중 하나가 될 수 있습니다.
146107
};
147108
```
148109

149110
실제 돌아가는 예시를 살펴보는 게 좋을 것 같네요. `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
161111

162112
```js run
163113
let user = {
@@ -176,16 +126,11 @@ alert(+user); // hint: number -> 1000
176126
alert(user + 500); // hint: default -> 1500
177127
```
178128

179-
<<<<<<< HEAD
180129
이렇게 메서드를 구현해 놓으면 `user`는 hint에 따라 (자기 자신을 설명해주는) 문자열로 변환되기도 하고 (가지고 있는 돈의 액수를 나타내는) 숫자로 변환되기도 합니다. `user[Symbol.toPrimitive]`를 사용하면 메서드 하나로 모든 종류의 형 변환을 다룰 수 있습니다.
181130

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
185131

186132
## toString과 valueOf
187133

188-
<<<<<<< HEAD
189134
`toString``valueOf`는 심볼이 생기기 이전부터 존재해 왔던 '평범한' 메서드입니다. 이 메서드를 이용하면 '구식'이긴 하지만 형 변환을 직접 구현할 수 있습니다.
190135

191136
객체에 `Symbol.toPrimitive`가 없으면 자바스크립트는 아래 규칙에 따라 `toString`이나 `valueOf`를 호출합니다.
@@ -194,16 +139,6 @@ As we can see from the code, `user` becomes a self-descriptive string or a money
194139
- 그 외: `valueOf -> toString`
195140

196141
이 메서드들은 반드시 원시값을 반환해야합니다. `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
207142

208143
일반 객체는 기본적으로 `toString``valueOf`에 적용되는 다음 규칙을 따릅니다.
209144

@@ -221,15 +156,9 @@ alert(user.valueOf() === user); // true
221156

222157
이런 이유 때문에 `alert`에 객체를 넘기면 `[object Object]`가 출력되는 것입니다.
223158

224-
<<<<<<< HEAD
225159
여기서 `valueOf`는 튜토리얼의 완성도를 높이고 헷갈리는 것을 줄여주려고 언급했습니다. 앞서 본 바와 같이 `valueOf`는 객체 자신을 반환하기 때문에 그 결과가 무시됩니다. 왜 그런거냐고 이유를 묻지는 말아주세요. 그냥 역사적인 이유때문입니다. 우리는 그냥 이 메서드가 존재하지 않는다고 생각하면 됩니다.
226160

227161
이제 직접 이 메서드들을 사용한 예시를 구현해봅시다.
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
233162

234163
아래 `user``toString``valueOf`를 조합해 만들었는데, `Symbol.toPrimitive`를 사용한 위쪽 예시와 동일하게 동작합니다.
235164

@@ -274,30 +203,19 @@ alert(user + 500); // toString -> John500
274203

275204
객체에 `Symbol.toPrimitive``valueOf`가 없으면, `toString`이 모든 형 변환을 처리합니다.
276205

277-
<<<<<<< HEAD
278-
## 반환 타입
279-
=======
280-
### A conversion can return any primitive type
281-
>>>>>>> upstream/master
206+
### 변환은 어떤 원시형이든 반환할 수 있습니다
282207

283208
위에서 소개해드린 세 개의 메서드는 'hint'에 명시된 자료형으로의 형 변환을 보장해 주지 않습니다.
284209

285-
<<<<<<< HEAD
286210
`toString()`이 항상 문자열을 반환하리라는 보장이 없고, `Symbol.toPrimitive`의 hint가 `"number"`일 때 항상 숫자형 자료가 반환되리라는 보장이 없습니다.
287-
=======
288-
There is no control whether `toString` returns exactly a string, or whether `Symbol.toPrimitive` method returns a number for the hint `"number"`.
289-
>>>>>>> upstream/master
290211

291212
확신할 수 있는 단 한 가지는 객체가 아닌 원시값을 반환해 준다는 것뿐입니다.
292213

293214
```smart header="과거의 잔재"
294215
`toString`이나 `valueOf`가 객체를 반환해도 에러가 발생하지 않습니다. 다만 이때는 반환 값이 무시되고, 메서드 자체가 존재하지 않았던 것처럼 동작합니다. 이렇게 동작하는 이유는 과거 자바스크립트엔 '에러'라는 개념이 잘 정립되어있지 않았기 때문입니다.
295216
296-
<<<<<<< HEAD
297217
반면에 `Symbol.toPrimitive`는 *무조건* 원시자료를 반환해야 합니다. 그렇지 않으면 에러가 발생합니다.
298-
=======
299218
In contrast, `Symbol.toPrimitive` is stricter, it *must* return a primitive, otherwise there will be an error.
300-
>>>>>>> upstream/master
301219
```
302220

303221
## 추가 형 변환
@@ -308,15 +226,11 @@ In contrast, `Symbol.toPrimitive` is stricter, it *must* return a primitive, oth
308226
1. 객체는 원시형으로 변화됩니다. 변환 규칙은 위에서 설명했습니다.
309227
2. 변환 후 원시값이 원하는 형이 아닌 경우엔 또다시 형 변환이 일어납니다.
310228

311-
<<<<<<< HEAD
312-
예시:
313-
=======
314-
If we pass an object as an argument, then there are two stages of calculations:
315-
1. The object is converted to a primitive (using the rules described above).
316-
2. If necessary for further calculations, the resulting primitive is also converted.
229+
객체를 인수로 전달하면, 연산은 다음 두 단계를 거쳐 진행됩니다.
230+
1. 객체는 (앞서 설명한 규칙에 따라) 원시값으로 변환됩니다.
231+
2. 추가 연산에 필요하다면, 결과로 나온 원시값이 한 번 더 변환됩니다.
317232

318-
For instance:
319-
>>>>>>> upstream/master
233+
예시:
320234

321235
```js run
322236
let obj = {
@@ -341,51 +255,26 @@ let obj = {
341255
}
342256
};
343257

344-
<<<<<<< HEAD
345258
alert(obj + 2); // 22("2" + 2), 문자열이 반환되기 때문에 문자열끼리의 병합이 일어났습니다.
346-
=======
347-
alert(obj + 2); // "22" ("2" + 2), conversion to primitive returned a string => concatenation
348-
>>>>>>> upstream/master
349259
```
350260

351261
## 요약
352262

353263
원시값을 기대하는 내장 함수나 연산자를 사용할 때 객체-원시형으로의 형 변환이 자동으로 일어납니다.
354264

355-
<<<<<<< HEAD
356265
객체-원시형으로의 형 변환은 hint를 기준으로 세 종류로 구분할 수 있습니다.
357266
- `"string"` (`alert` 같이 문자열을 필요로 하는 연산)
358267
- `"number"` (수학 연산)
359268
- `"default"` (드물게 발생함)
360269

361270
연산자별로 어떤 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
370271

371272
객체-원시형 변환엔 다음 알고리즘이 적용됩니다.
372273

373-
<<<<<<< HEAD
374274
1. 객체에 `obj[Symbol.toPrimitive](hint)`메서드가 있는지 찾고, 있다면 호출합니다.
375275
2. 1에 해당하지 않고 hint가 `"string"`이라면,
376276
- `obj.toString()`이나 `obj.valueOf()`를 호출합니다.
377277
3. 1과 2에 해당하지 않고, hint가 `"number"``"default"`라면
378278
- `obj.valueOf()``obj.toString()`을 호출합니다.
379279

380280
`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.
391-
>>>>>>> upstream/master

0 commit comments

Comments
 (0)