Skip to content

Commit c437dba

Browse files
committed
[충돌해결 및 번역] Part1 6.9 call/apply와 데코레이터, 포워딩
1 parent 4eab8aa commit c437dba

1 file changed

Lines changed: 32 additions & 54 deletions

File tree

  • 1-js/06-advanced-functions/09-call-apply-decorators

1-js/06-advanced-functions/09-call-apply-decorators/article.md

Lines changed: 32 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# call/apply와 데코레이터, 포워딩
22

3-
자바스크립트는 함수를 다룰 때 탁월한 유연성을 제공합니다. 함수는 이곳저곳 전달될 수 있고, 객체로도 사용될 수 있습니다. 이번 챕터에선 함수 간에 호출을 어떻게 *포워딩(forwarding)* 하는지, 함수를 어떻게 *데코레이팅(decorating)* 하는지에 대해 알아보겠습니다.
3+
자바스크립트는 함수를 다룰 때 탁월한 유연성을 제공합니다. 함수는 이곳저곳 전달될 수 있고, 객체로도 사용될 수 있습니다. 이번 챕터에선 함수 간에 호출을 어떻게 _포워딩(forwarding)_ 하는지, 함수를 어떻게 _데코레이팅(decorating)_ 하는지에 대해 알아보겠습니다.
44

55
## 코드 변경 없이 캐싱 기능 추가하기
66

@@ -22,40 +22,33 @@ function slow(x) {
2222
function cachingDecorator(func) {
2323
let cache = new Map();
2424

25-
return function(x) {
26-
if (cache.has(x)) { // cache에 해당 키가 있으면
25+
return function (x) {
26+
if (cache.has(x)) {
27+
// cache에 해당 키가 있으면
2728
return cache.get(x); // 대응하는 값을 cache에서 읽어옵니다.
2829
}
2930

30-
let result = func(x); // 그렇지 않은 경우엔 func를 호출하고,
31+
let result = func(x); // 그렇지 않은 경우엔 func를 호출하고,
3132

32-
cache.set(x, result); // 그 결과를 캐싱(저장)합니다.
33+
cache.set(x, result); // 그 결과를 캐싱(저장)합니다.
3334
return result;
3435
};
3536
}
3637

3738
slow = cachingDecorator(slow);
3839

39-
<<<<<<< HEAD
40-
alert( slow(1) ); // slow(1)이 저장되었습니다.
41-
alert( "다시 호출: " + slow(1) ); // 동일한 결과
40+
alert( slow(1) ); // slow(1)를 캐싱하고 결과를 반환합니다.
41+
alert( "다시 호출: " + slow(1) ); // 캐시에서 slow(1)의 결과를 가져옵니다.
4242

43-
alert( slow(2) ); // slow(2)가 저장되었습니다.
44-
alert( "다시 호출: " + slow(2) ); // 윗줄과 동일한 결과
45-
=======
46-
alert( slow(1) ); // slow(1) is cached and the result returned
47-
alert( "Again: " + slow(1) ); // slow(1) result returned from cache
48-
49-
alert( slow(2) ); // slow(2) is cached and the result returned
50-
alert( "Again: " + slow(2) ); // slow(2) result returned from cache
51-
>>>>>>> upstream/master
43+
alert( slow(2) ); // slow(2)를 캐싱하고 결과를 반환합니다.
44+
alert( "다시 호출: " + slow(2) ); // 캐시에서 slow(2)의 결과를 가져옵니다.
5245
```
5346

54-
`cachingDecorator`같이 인수로 받은 함수의 행동을 변경시켜주는 함수를 *데코레이터(decorator)* 라고 부릅니다.
47+
`cachingDecorator`같이 인수로 받은 함수의 행동을 변경시켜주는 함수를 _데코레이터(decorator)_ 라고 부릅니다.
5548

5649
모든 함수를 대상으로 `cachingDecorator`를 호출 할 수 있는데, 이때 반환되는 것은 캐싱 래퍼입니다. 함수에 `cachingDecorator`를 적용하기만 하면 캐싱이 가능한 함수를 원하는 만큼 구현할 수 있기 때문에 데코레이터 함수는 아주 유용하게 사용됩니다.
5750

58-
캐싱 관련 코드를 함수 코드와 분리할 수 있기 때문에 함수의 코드가 간결해진다는 장점도 있습니다.
51+
캐싱 관련 코드를 함수 코드와 분리할 수 있기 때문에 함수의 코드가 간결해진다는 장점도 있습니다.
5952

6053
아래 그림에서 볼 수 있듯이 `cachingDecorator(func)`를 호출하면 '래퍼(wrapper)', `function(x)`이 반환됩니다. 래퍼 `function(x)``func(x)`의 호출 결과를 캐싱 로직으로 감쌉니다(wrapping).
6154

@@ -66,7 +59,7 @@ alert( "Again: " + slow(2) ); // slow(2) result returned from cache
6659
`slow` 본문을 수정하는 것 보다 독립된 래퍼 함수 `cachingDecorator`를 사용할 때 생기는 이점을 정리하면 다음과 같습니다.
6760

6861
- `cachingDecorator`를 재사용 할 수 있습니다. 원하는 함수 어디에든 `cachingDecorator`를 적용할 수 있습니다.
69-
- 캐싱 로직이 분리되어 `slow` 자체의 복잡성이 증가하지 않습니다.
62+
- 캐싱 로직이 분리되어 `slow` 자체의 복잡성이 증가하지 않습니다.
7063
- 필요하다면 여러 개의 데코레이터를 조합해서 사용할 수도 있습니다(추가 데코레이터는 `cachingDecorator` 뒤를 따릅니다).
7164

7265
## 'func.call'를 사용해 컨텍스트 지정하기
@@ -139,9 +132,10 @@ func.call(context, arg1, arg2, ...)
139132
메서드를 호출하면 메서드의 첫 번째 인수가 `this`, 이어지는 인수가 `func`의 인수가 된 후, `func`이 호출됩니다.
140133

141134
아래 함수와 메서드를 호출하면 거의 동일한 일이 발생합니다.
135+
142136
```js
143137
func(1, 2, 3);
144-
func.call(obj, 1, 2, 3)
138+
func.call(obj, 1, 2, 3);
145139
```
146140

147141
둘 다 인수로 `1`, `2`, `3`을 받죠. 유일한 차이점은 `func.call`에선 `this``obj`로 고정된다는 점입니다.
@@ -157,22 +151,21 @@ let user = { name: "John" };
157151
let admin = { name: "Admin" };
158152

159153
// call을 사용해 원하는 객체가 'this'가 되도록 합니다.
160-
sayHi.call( user ); // this = John
161-
sayHi.call( admin ); // this = Admin
154+
sayHi.call(user); // this = John
155+
sayHi.call(admin); // this = Admin
162156
```
163157

164158
아래 예시에선 `call`을 사용해 컨텍스트와 `phrase`에 원하는 값을 지정해 보았습니다.
165159

166-
167160
```js run
168161
function say(phrase) {
169-
alert(this.name + ': ' + phrase);
162+
alert(this.name + ": " + phrase);
170163
}
171164

172165
let user = { name: "John" };
173166

174167
// this엔 user가 고정되고, "Hello"는 메서드의 첫 번째 인수가 됩니다.
175-
say.call( user, "Hello" ); // John: Hello
168+
say.call(user, "Hello"); // John: Hello
176169
```
177170

178171
래퍼 안에서 `call`을 사용해 컨텍스트를 원본 함수로 전달하면 에러가 발생하지 않습니다.
@@ -227,7 +220,7 @@ alert( worker.slow(2) ); // 제대로 동작합니다. 다만, 원본 함수가
227220
let worker = {
228221
slow(min, max) {
229222
return min + max; // CPU를 아주 많이 쓰는 작업이라고 가정
230-
}
223+
},
231224
};
232225

233226
// 동일한 인수를 전달했을 때 호출 결과를 기억할 수 있어야 합니다.
@@ -240,7 +233,7 @@ worker.slow = cachingDecorator(worker.slow);
240233

241234
1. 복수 키를 지원하는 맵과 유사한 자료 구조 구현하기(서드 파티 라이브러리 등을 사용해도 됨)
242235
2. 중첩 맵을 사용하기. `(max, result)` 쌍 저장은 `cache.set(min)`으로, `result``cache.get(min).get(max)`을 사용해 얻습니다.
243-
3. 두 값을 하나로 합치기. ``의 키로 문자열 `"min,max"`를 사용합니다. 여러 값을 하나로 합치는 코드는 *해싱 함수(hashing function)* 에 구현해 유연성을 높입니다.
236+
3. 두 값을 하나로 합치기. ``의 키로 문자열 `"min,max"`를 사용합니다. 여러 값을 하나로 합치는 코드는 _해싱 함수(hashing function)_ 에 구현해 유연성을 높입니다.
244237

245238
세 번째 방법만으로 충분하기 때문에 이 방법을 사용해 코드를 수정해 보겠습니다.
246239

@@ -299,7 +292,7 @@ alert( "다시 호출: " + worker.slow(3, 5) ); // 동일한 결과 출력(캐
299292
내장 메서드 [func.apply](mdn:js/Function/apply)의 문법은 다음과 같습니다.
300293

301294
```js
302-
func.apply(context, args)
295+
func.apply(context, args);
303296
```
304297

305298
`apply``func``this``context`로 고정해주고, 유사 배열 객체인 `args`를 인수로 사용할 수 있게 해줍니다.
@@ -309,39 +302,24 @@ func.apply(context, args)
309302
따라서 아래 코드 두 줄은 거의 같은 역할을 합니다.
310303

311304
```js
312-
<<<<<<< HEAD
313-
func.call(context, ...args); // 전개 구문을 사용해 인수가 담긴 배열을 전달하는 것과
314-
func.apply(context, args); // call을 사용하는 것은 동일합니다.
315-
```
316-
317-
그런데 약간의 차이가 있긴 합니다.
318-
=======
319305
func.call(context, ...args);
320306
func.apply(context, args);
321307
```
322308

323-
They perform the same call of `func` with given context and arguments.
309+
위 코드는 `func`을 동일한 컨텍스트와 인수로 호출합니다.
310+
그런데 `args`에 관해 약간의 차이가 있긴 합니다.
324311

325-
There's only a subtle difference regarding `args`:
326-
>>>>>>> upstream/master
327-
328-
- 전개 구문 `...`은 *이터러블* `args`을 분해 해 `call`에 전달할 수 있도록 해줍니다.
329-
- `apply`는 오직 *유사 배열* 형태의 `args`만 받습니다.
330-
331-
<<<<<<< HEAD
332-
이 차이만 빼면 두 메서드는 완전히 동일하게 동작합니다. 인수가 이터러블 형태라면 `call`을, 유사 배열 형태라면 `apply`를 사용하면 됩니다.
312+
- 전개 구문 `...`_이터러블_ `args`을 분해 해 `call`에 전달할 수 있도록 해줍니다.
313+
- `apply`는 오직 _유사 배열_ 형태의 `args`만 받습니다.
333314

334315
배열같이 이터러블이면서 유사 배열인 객체엔 둘 다를 사용할 수 있는데, 대부분의 자바스크립트 엔진은 내부에서 `apply`를 최적화 하기 때문에 `apply`를 사용하는 게 좀 더 빠르긴 합니다.
335-
=======
336-
...And for objects that are both iterable and array-like, such as a real array, we can use any of them, but `apply` will probably be faster, because most JavaScript engines internally optimize it better.
337-
>>>>>>> upstream/master
338316

339-
이렇게 컨텍스트와 함께 인수 전체를 다른 함수에 전달하는 것을 *콜 포워딩(call forwarding)* 이라고 합니다.
317+
이렇게 컨텍스트와 함께 인수 전체를 다른 함수에 전달하는 것을 _ 포워딩(call forwarding)_ 이라고 합니다.
340318

341319
가장 간단한 형태의 콜 포워딩은 다음과 같습니다.
342320

343321
```js
344-
let wrapper = function() {
322+
let wrapper = function () {
345323
return func.apply(this, arguments);
346324
};
347325
```
@@ -354,11 +332,11 @@ let wrapper = function() {
354332

355333
```js
356334
function hash(args) {
357-
return args[0] + ',' + args[1];
335+
return args[0] + "," + args[1];
358336
}
359337
```
360338

361-
지금 상태에선 인수 두 개만 다룰 수 있습니다. `args`의 요소 개수에 상관없이 요소들을 합칠 수 있으면 더 좋겠네요.
339+
지금 상태에선 인수 두 개만 다룰 수 있습니다. `args`의 요소 개수에 상관없이 요소들을 합칠 수 있으면 더 좋겠네요.
362340

363341
가장 자연스러운 해결책은 배열 메서드 [arr.join](mdn:js/Array/join)을 사용하는 것입니다.
364342

@@ -394,7 +372,7 @@ function hash() {
394372
hash(1, 2);
395373
```
396374

397-
The trick is called *method borrowing*.
375+
The trick is called _method borrowing_.
398376

399377
일반 배열에서 `join` 메서드를 빌려오고(`[].join`), `[].join.call`를 사용해 `arguments`를 컨텍스트로 고정한 후 `join`메서드를 호출하는 것이죠.
400378

@@ -438,7 +416,7 @@ The trick is called *method borrowing*.
438416
*콜 포워딩*은 대개 `apply`를 사용해 구현합니다.
439417

440418
```js
441-
let wrapper = function() {
419+
let wrapper = function () {
442420
return original.apply(this, arguments);
443421
};
444422
```

0 commit comments

Comments
 (0)