Skip to content

Commit 62b4912

Browse files
committed
fix: Prettier 자동 포맷팅 되돌리기 및 충돌 재해결
1 parent 6e344ed commit 62b4912

8 files changed

Lines changed: 106 additions & 120 deletions

File tree

1-js/06-advanced-functions/07-new-function/article.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
# new Function 문법
23

34
함수 표현식과 함수 선언문 이외에 함수를 만들 수도 있는 방법이 하나 더 있습니다. 잘 사용하는 방법은 아니지만, 이 방법 외에는 대안이 없을 때 사용합니다.
@@ -7,17 +8,17 @@
78
`new Function` 문법을 사용하면 함수를 만들 수 있습니다.
89

910
```js
10-
let func = new Function([arg1, arg2, ...argN], functionBody);
11+
let func = new Function ([arg1, arg2, ...argN], functionBody);
1112
```
1213

1314
새로 만들어지는 함수는 인수 `arg1...argN`과 함수 본문 `functionBody`로 구성됩니다.
1415

1516
인수 두 개가 있는 함수를 직접 만들어 보면서 `new Function` 문법에 대해 이해해보도록 합시다.
1617

1718
```js run
18-
let sum = new Function("a", "b", "return a + b");
19+
let sum = new Function('a', 'b', 'return a + b');
1920

20-
alert(sum(1, 2)); // 3
21+
alert( sum(1, 2) ); // 3
2122
```
2223

2324
인수가 없고 함수 본문만 있는 함수를 만들어보겠습니다.
@@ -45,11 +46,11 @@ func();
4546

4647
## 클로저
4748

48-
함수는 특별한 프로퍼티 `[[Environment]]`에 저장된 정보를 이용해 자기 자신이 태어난 곳을 기억합니다. `[[Environment]]`는 함수가 만들어진 렉시컬 환경을 참조합니다(자세한 내용은 <info:closure>에서 다루었습니다).
49+
함수는 특별한 프로퍼티 `[[Environment]]`에 저장된 정보를 이용해 자기 자신이 태어난 곳을 기억합니다. `[[Environment]]`는 함수가 만들어진 렉시컬 환경을 참조합니다(자세한 내용은 <info:closure>에서 다루었습니다).
4950

5051
그런데 `new Function`을 이용해 함수를 만들면 함수의 `[[Environment]]` 프로퍼티가 현재 렉시컬 환경이 아닌 전역 렉시컬 환경을 참조하게 됩니다.
5152

52-
따라서 `new Function`을 이용해 만든 함수는 외부 변수에 접근할 수 없고, 오직 전역 변수에만 접근할 수 있습니다.
53+
따라서 `new Function`을 이용해 만든 함수는 외부 변수에 접근할 수 없고, 오직 전역 변수에만 접근할 수 있습니다.
5354

5455
```js run
5556
function getFunc() {
@@ -89,7 +90,7 @@ getFunc()(); // getFunc의 렉시컬 환경에 있는 값 *!*"test"*/!*가 출
8990

9091
`new Function`으로 만든 새로운 함수 내부에서 외부 변수에 접근하려 할 때, 기존 함수 선언 방식으로 작성한 함수와 동일한 동작이 보장되어야 하죠.
9192

92-
그런데 스크립트가 프로덕션 서버에 반영되기 전, _압축기(minifier)_ 에 의해 압축될 때 문제가 발생합니다. 압축기는 스크립트에서 주석이나 여분의 공백 등을 없애 코드 크기를 줄여주는 특수한 프로그램인데 압축기가 지역 변수 이름을 짧게 바꾸면서 문제가 발생하죠.
93+
그런데 스크립트가 프로덕션 서버에 반영되기 전, *압축기(minifier)* 에 의해 압축될 때 문제가 발생합니다. 압축기는 스크립트에서 주석이나 여분의 공백 등을 없애 코드 크기를 줄여주는 특수한 프로그램인데 압축기가 지역 변수 이름을 짧게 바꾸면서 문제가 발생하죠.
9394

9495
구체적으로 어떤 부분이 문제가 되는지 예시를 통해 알아봅시다. 함수 내부에 `let userName`라는 변수가 있으면 이 지역변수는 압축기에 의해 `let a` 등(해당 글자가 이미 사용 중이라면 다른 짧은 이름)으로 대체되는데, 이때 `userName` 모두가 `a`로 교체됩니다. `userName`은 지역변수이고, 함수 외부에선 함수 내부에 있는 변수에 접근할 수 없기 때문에 이렇게 해도 전혀 문제가 없죠. 압축기는 단순히 찾아바꾸기가 아니라 코드 구조를 분석해 기존 코드의 기능을 망가뜨리지 않으면서 영리하게 제 역할을 수행합니다.
9596

@@ -106,17 +107,17 @@ getFunc()(); // getFunc의 렉시컬 환경에 있는 값 *!*"test"*/!*가 출
106107
문법:
107108

108109
```js
109-
let func = new Function([arg1, arg2, ...argN], functionBody);
110+
let func = new Function ([arg1, arg2, ...argN], functionBody);
110111
```
111112

112113
인수를 한꺼번에 모아(쉼표로 구분) 전달할 수도 있습니다.
113114

114115
아래 세 선언 방식은 동일하게 동작하죠.
115116

116117
```js
117-
new Function("a", "b", "return a + b"); // 기본 문법
118-
new Function("a,b", "return a + b"); // 쉼표로 구분
119-
new Function("a , b", "return a + b"); // 쉼표와 공백으로 구분
118+
new Function('a', 'b', 'return a + b'); // 기본 문법
119+
new Function('a,b', 'return a + b'); // 쉼표로 구분
120+
new Function('a , b', 'return a + b'); // 쉼표와 공백으로 구분
120121
```
121122

122123
`new Function`을 이용해 만든 함수의 `[[Environment]]`는 외부 렉시컬 환경이 아닌 전역 렉시컬 환경을 참조하므로 외부 변수를 사용할 수 없습니다. 단점 같아 보이는 특징이긴 하지만 에러를 예방해 준다는 관점에선 장점이 되기도 합니다. 구조상으론 매개변수를 사용해 값을 받는 게 더 낫습니다. 압축기에 의한 에러도 방지할 수 있죠.

1-js/06-advanced-functions/08-settimeout-setinterval/article.md

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ setTimeout("alert('안녕하세요.')", 1000);
6464
그런데 이렇게 문자열을 사용하는 방법은 추천하지 않습니다. 되도록 다음 예시와 같이 익명 화살표 함수를 사용하세요.
6565

6666
```js run no-beautify
67-
setTimeout(() => alert("안녕하세요."), 1000);
67+
setTimeout(() => alert('안녕하세요.'), 1000);
6868
```
6969

7070
````smart header="함수를 실행하지 말고 넘기세요."
@@ -120,21 +120,17 @@ let timerId = setInterval(func|code, [delay], [arg1], [arg2], ...)
120120

121121
```js run
122122
// 2초 간격으로 메시지를 보여줌
123-
let timerId = setInterval(() => alert("째깍"), 2000);
123+
let timerId = setInterval(() => alert('째깍'), 2000);
124124

125125
// 5초 후에 정지
126-
setTimeout(() => {
127-
clearInterval(timerId);
128-
alert("정지");
129-
}, 5000);
126+
setTimeout(() => { clearInterval(timerId); alert('정지'); }, 5000);
130127
```
131128

132-
```smart header="`alert`창이 떠 있더라도 타이머는 멈추지 않습니다."
133-
Chrome과 Firefox를 포함한 대부분의 브라우저는`alert/confirm/prompt` 창이 떠 있는 동안에도 내부 타이머를 멈추지 않습니다.
129+
```smart header="`alert` 창이 떠 있더라도 타이머는 멈추지 않습니다."
130+
Chrome과 Firefox를 포함한 대부분의 브라우저는 `alert/confirm/prompt` 창이 떠 있는 동안에도 내부 타이머를 멈추지 않습니다.
134131

135132
위 예시를 실행하고 첫 번째 `alert` 창이 떴을 때 몇 초간 기다렸다가 창을 닫으면, 두 번째 `alert` 창이 바로 나타나는 것을 보고 이를 확인할 수 있습니다. 이런 이유로 얼럿 창은 명시한 지연 시간인 2초보다 더 짧은 간격으로 뜨게 됩니다.
136-
137-
````
133+
```
138134
139135
## 중첩 setTimeout
140136
@@ -153,7 +149,7 @@ let timerId = setTimeout(function tick() {
153149
timerId = setTimeout(tick, 2000); // (*)
154150
*/!*
155151
}, 2000);
156-
````
152+
```
157153

158154
다섯 번째 줄의 `setTimeout``(*)`로 표시한 줄의 실행이 종료되면 다음 호출을 스케줄링합니다.
159155

@@ -162,7 +158,6 @@ let timerId = setTimeout(function tick() {
162158
5초 간격으로 서버에 요청을 보내 데이터를 얻는다고 가정해 봅시다. 서버가 과부하 상태라면 요청 간격을 10초, 20초, 40초 등으로 증가시켜주는 게 좋을 겁니다.
163159

164160
아래는 이를 구현한 의사 코드입니다.
165-
166161
```js
167162
let delay = 5000;
168163

@@ -179,6 +174,7 @@ let timerId = setTimeout(function request() {
179174
}, delay);
180175
```
181176

177+
182178
CPU 소모가 많은 작업을 주기적으로 실행하는 경우에도 `setTimeout`을 재귀 실행하는 방법이 유용합니다. 작업에 걸리는 시간에 따라 다음 작업을 유동적으로 계획할 수 있기 때문입니다.
183179

184180
**중첩 `setTimeout`을 이용하는 방법은 지연 간격을 보장하지만 `setInterval`은 이를 보장하지 않습니다.**
@@ -187,7 +183,7 @@ CPU 소모가 많은 작업을 주기적으로 실행하는 경우에도 `setTim
187183

188184
```js
189185
let i = 1;
190-
setInterval(function () {
186+
setInterval(function() {
191187
func(i++);
192188
}, 100);
193189
```
@@ -214,7 +210,7 @@ setTimeout(function run() {
214210

215211
그렇다면 `func`을 실행하는 데 걸리는 시간이 명시한 지연 간격보다 길 때 어떤 일이 발생할까요?
216212

217-
이런 경우는 엔진이 `func`의 실행이 종료될 때까지 기다려줍니다. `func`의 실행이 종료되면 엔진은 스케줄러를 확인하고, 지연 시간이 지났으면 다음 호출을 _바로_ 시작합니다.
213+
이런 경우는 엔진이 `func`의 실행이 종료될 때까지 기다려줍니다. `func`의 실행이 종료되면 엔진은 스케줄러를 확인하고, 지연 시간이 지났으면 다음 호출을 *바로* 시작합니다.
218214

219215
따라서 함수 호출에 걸리는 시간이 매번 `delay` 밀리초보다 길면, 모든 함수가 쉼 없이 계속 연속 호출됩니다.
220216

@@ -260,7 +256,7 @@ alert("Hello");
260256
대기 시간이 0인 setTimeout을 활용한 브라우저 환경에서의 유스 케이스는 <info:event-loop>에서 자세히 다루도록 하겠습니다.
261257

262258
````smart header="실제로 지연시간이 0인 경우는 없습니다(브라우저 환경)."
263-
브라우저는 [HTML Living Standard](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers)에서 정한 중첩 타이머 실행 간격 관련 제약을 준수합니다. 해당 표준엔 "다섯 번째 중첩 타이머 이후엔 대기 시간을 최소 4밀리초 이상으로 강제해야 한다."라는 제약이 명시되어 있습니다.
259+
브라우저는 [HTML Living Standard](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers)에서 정한 중첩 타이머 실행 간격 관련 제약을 준수합니다. 해당 표준엔 "다섯 번째 중첩 타이머 이후엔 대기 시간을 최소 4밀리초 이상으로 강제해야 한다."라는 제약을 명시합니다.
264260
265261
예시를 보며 이 제약 사항을 이해해봅시다. 예시 내 `setTimeout`은 지연 없이 함수 run을 다시 호출할 수 있게 스케줄링 되어 있습니다. 배열 `times`에는 실제 지연 간격에 대한 정보가 기록되도록 해놓았는데, 배열 times에 어떤 값이 저장되는지 알아봅시다.
266262

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

Lines changed: 26 additions & 26 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,15 +22,14 @@ function slow(x) {
2222
function cachingDecorator(func) {
2323
let cache = new Map();
2424

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

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

33-
cache.set(x, result); // 그 결과를 캐싱(저장)합니다.
32+
cache.set(x, result); // 그 결과를 캐싱(저장)합니다.
3433
return result;
3534
};
3635
}
@@ -44,11 +43,11 @@ alert( slow(2) ); // slow(2)를 캐싱하고 결과를 반환합니다.
4443
alert( "다시 호출: " + slow(2) ); // 캐시에서 slow(2)의 결과를 가져옵니다.
4544
```
4645

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

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

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

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

@@ -59,7 +58,7 @@ alert( "다시 호출: " + slow(2) ); // 캐시에서 slow(2)의 결과를 가
5958
`slow` 본문을 수정하는 것 보다 독립된 래퍼 함수 `cachingDecorator`를 사용할 때 생기는 이점을 정리하면 다음과 같습니다.
6059

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

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

134133
아래 함수와 메서드를 호출하면 거의 동일한 일이 발생합니다.
135-
136134
```js
137135
func(1, 2, 3);
138-
func.call(obj, 1, 2, 3);
136+
func.call(obj, 1, 2, 3)
139137
```
140138

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

153151
// call을 사용해 원하는 객체가 'this'가 되도록 합니다.
154-
sayHi.call(user); // this = John
155-
sayHi.call(admin); // this = Admin
152+
sayHi.call( user ); // this = John
153+
sayHi.call( admin ); // this = Admin
156154
```
157155

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

158+
160159
```js run
161160
function say(phrase) {
162-
alert(this.name + ": " + phrase);
161+
alert(this.name + ': ' + phrase);
163162
}
164163

165164
let user = { name: "John" };
166165

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

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

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

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

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

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

294293
```js
295-
func.apply(context, args);
294+
func.apply(context, args)
296295
```
297296

298297
`apply``func``this``context`로 고정해주고, 유사 배열 객체인 `args`를 인수로 사용할 수 있게 해줍니다.
@@ -307,19 +306,20 @@ func.apply(context, args);
307306
```
308307

309308
위 코드는 `func`을 동일한 컨텍스트와 인수로 호출합니다.
309+
310310
그런데 `args`에 관해 약간의 차이가 있긴 합니다.
311311

312-
- 전개 구문 `...`_이터러블_ `args`을 분해 해 `call`에 전달할 수 있도록 해줍니다.
313-
- `apply`는 오직 _유사 배열_ 형태의 `args`만 받습니다.
312+
- 전개 구문 `...`*이터러블* `args`을 분해 해 `call`에 전달할 수 있도록 해줍니다.
313+
- `apply`는 오직 *유사 배열* 형태의 `args`만 받습니다.
314314

315315
배열같이 이터러블이면서 유사 배열인 객체엔 둘 다를 사용할 수 있는데, 대부분의 자바스크립트 엔진은 내부에서 `apply`를 최적화 하기 때문에 `apply`를 사용하는 게 좀 더 빠르긴 합니다.
316316

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

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

321321
```js
322-
let wrapper = function () {
322+
let wrapper = function() {
323323
return func.apply(this, arguments);
324324
};
325325
```
@@ -332,11 +332,11 @@ let wrapper = function () {
332332

333333
```js
334334
function hash(args) {
335-
return args[0] + "," + args[1];
335+
return args[0] + ',' + args[1];
336336
}
337337
```
338338

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

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

@@ -372,7 +372,7 @@ function hash() {
372372
hash(1, 2);
373373
```
374374

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

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

@@ -416,7 +416,7 @@ The trick is called _method borrowing_.
416416
*콜 포워딩*은 대개 `apply`를 사용해 구현합니다.
417417

418418
```js
419-
let wrapper = function () {
419+
let wrapper = function() {
420420
return original.apply(this, arguments);
421421
};
422422
```

1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
에러는 `askPassword`가 함수 `loginOk`, `loginFail`을 객체 없이 가지고 오기 때문에 발생합니다.
23

34
ask는 `loginOk`, `loginFail`을 호출할 때 `this=undefined`라고 자연스레 가정합니다.
@@ -32,13 +33,9 @@ askPassword(user.loginOk.bind(user), user.loginFail.bind(user));
3233
이제 잘 동작합니다.
3334

3435
이 외에도 다른 답이 있는데, 아래에서 확인 가능합니다.
35-
3636
```js
3737
//...
38-
askPassword(
39-
() => user.loginOk(),
40-
() => user.loginFail(),
41-
);
38+
askPassword(() => user.loginOk(), () => user.loginFail());
4239
```
4340

4441
이렇게 화살표 함수를 사용하는 방법 또한 대개 잘 동작하며 가독성도 좋습니다.

0 commit comments

Comments
 (0)