Skip to content
6 changes: 1 addition & 5 deletions 1-js/06-advanced-functions/07-new-function/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,7 @@ getFunc()(); // getFunc의 렉시컬 환경에 있는 값 *!*"test"*/!*가 출

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

<<<<<<< HEAD
구체적으로 어떤 부분이 문제가 되는지 예시를 통해 알아봅시다. 함수 내부에 `let userName`라는 변수가 있으면 이 지역변수는 압축기에 의해 `let a` 등(짧은 이름)으로 대체되는데, 이때 `userName` 모두가 `a`로 교체됩니다. `userName`은 지역변수이고, 함수 외부에선 함수 내부에 있는 변수에 접근할 수 없기 때문에 이렇게 해도 전혀 문제가 없죠. 압축기는 단순히 변수를 찾아서 바꾸지 않고 코드 구조를 분석해 기존에 작성한 코드의 기능을 망가뜨리지 않으면서 영리하게 제 역할을 수행합니다.
=======
For instance, if a function has `let userName`, minifier replaces it with `let a` (or another letter if this one is occupied), and does it everywhere. That's usually a safe thing to do, because the variable is local, nothing outside the function can access it. And inside the function, minifier replaces every mention of it. Minifiers are smart, they analyze the code structure, so they don't break anything. They're not just a dumb find-and-replace.
>>>>>>> upstream/master
구체적으로 어떤 부분이 문제가 되는지 예시를 통해 알아봅시다. 함수 내부에 `let userName`라는 변수가 있으면 이 지역변수는 압축기에 의해 `let a` 등(해당 글자가 이미 사용 중이라면 다른 짧은 이름)으로 대체되는데, 이때 `userName` 모두가 `a`로 교체됩니다. `userName`은 지역변수이고, 함수 외부에선 함수 내부에 있는 변수에 접근할 수 없기 때문에 이렇게 해도 전혀 문제가 없죠. 압축기는 단순히 찾아바꾸기가 아니라 코드 구조를 분석해 기존 코드의 기능을 망가뜨리지 않으면서 영리하게 제 역할을 수행합니다.

이런 동작 방식 때문에 `new Function` 문법으로 만든 함수 내부에서 외부 변수에 접근하려고 하면 `userName`은 이미 이름이 변경되었기 때문에 찾을 수 없게 됩니다.

Expand Down
64 changes: 10 additions & 54 deletions 1-js/06-advanced-functions/08-settimeout-setinterval/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,7 @@ let timerId = setTimeout(func|code, [delay], [arg1], [arg2], ...)
: 실행 전 대기 시간으로, 단위는 밀리초(millisecond, 1000밀리초 = 1초)이며 기본값은 0입니다.

`arg1`, `arg2`...
<<<<<<< HEAD
: 함수에 전달할 인수들로, IE9 이하에선 지원하지 않습니다.
=======
: Arguments for the function
>>>>>>> upstream/master
: 함수에 전달할 인수입니다.

예시를 통해 `setTimeout`을 어떻게 쓸 수 있는지 알아봅시다. 아래 코드를 실행하면 1초 후에 `sayHi()`가 호출됩니다.

Expand Down Expand Up @@ -106,11 +102,7 @@ alert(timerId); // 위 타이머 식별자와 동일함 (취소 후에도 식별

다시 한번 말씀드리자면, 스케줄링에 관한 명세는 따로 존재하지 않습니다. 명세가 없기 때문에 호스트 환경마다 약간의 차이가 있을 수밖에 없습니다.

<<<<<<< HEAD
참고로 브라우저는 HTML5의 [timers section](https://www.w3.org/TR/html5/webappapis.html#timers)을 준수하고 있습니다.
=======
For browsers, timers are described in the [timers section](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers) of HTML Living Standard.
>>>>>>> upstream/master
참고로 브라우저는 HTML Living Standard의 [timers section](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers)을 준수하고 있습니다.

## setInterval

Expand All @@ -137,11 +129,7 @@ setTimeout(() => { clearInterval(timerId); alert('정지'); }, 5000);
```smart header="`alert` 창이 떠 있더라도 타이머는 멈추지 않습니다."
Chrome과 Firefox를 포함한 대부분의 브라우저는 `alert/confirm/prompt` 창이 떠 있는 동안에도 내부 타이머를 멈추지 않습니다.

<<<<<<< HEAD
위 예시를 실행하고 첫 번째 `alert` 창이 떴을 때 몇 초간 기다렸다가 창을 닫으면, 두 번째 `alert` 창이 바로 나타나는 것을 보고 이를 확인할 수 있습니다. 이런 이유로 얼럿 창은 명시한 지연 시간인 2초보다 더 짧은 간격으로 뜨게 됩니다.
=======
So if you run the code above and don't dismiss the `alert` window for some time, then the next `alert` will be shown immediately as you do it. The actual interval between alerts will be shorter than 2 seconds.
>>>>>>> upstream/master
```

## 중첩 setTimeout
Expand Down Expand Up @@ -230,11 +218,7 @@ setTimeout(function run() {

![](settimeout-interval.svg)

<<<<<<< HEAD
**중첩 `setTimeout`을 사용하면 명시한 지연(여기서는 100ms)이 보장됩니다.**
=======
**The nested `setTimeout` ensures a minimum delay (100ms here) between the end of one call and the beginning of the subsequent one.**
>>>>>>> upstream/master
**중첩 `setTimeout`을 사용하면 이전 호출이 끝난 후 다음 호출이 시작되기까지 명시한 지연(여기서는 100ms)이 보장됩니다.**

이렇게 지연 간격이 보장되는 이유는 이전 함수의 실행이 종료된 이후에 다음 함수 호출에 대한 계획이 세워지기 때문입니다.

Expand All @@ -248,11 +232,7 @@ setTimeout(function() {...}, 100);

`setInterval`의 경우는, `clearInterval`이 호출되기 전까지 함수에 대한 참조가 메모리에 유지됩니다.

<<<<<<< HEAD
그런데 이런 동작 방식에는 부작용이 하나 있습니다. 외부 렉시컬 환경을 참조하는 함수가 있다고 가정해 봅시다. 이 함수가 메모리에 남아있는 동안엔 외부 변수 역시 메모리에 남아있기 마련입니다. 그런데 이렇게 되면 실제 함수가 차지했어야 하는 공간보다 더 많은 메모리 공간이 사용됩니다. 이런 부작용을 방지하고 싶다면 스케줄링할 필요가 없어진 함수는 아무리 작더라도 취소하도록 합시다.
=======
There's a side effect. A function references the outer lexical environment, so, while it lives, outer variables live too. They may take much more memory than the function itself. So when we don't need the scheduled function anymore, it's better to cancel it, even if it's very small.
>>>>>>> upstream/master
````

## 대기 시간이 0인 setTimeout
Expand All @@ -275,13 +255,8 @@ alert("Hello");

대기 시간이 0인 setTimeout을 활용한 브라우저 환경에서의 유스 케이스는 <info:event-loop>에서 자세히 다루도록 하겠습니다.

<<<<<<< HEAD
````smart header="브라우저 환경에서 실제 대기 시간은 0이 아닙니다."
브라우저는 [HTML5 표준](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers)에서 정한 중첩 타이머 실행 간격 관련 제약을 준수합니다. 해당 표준엔 "다섯 번째 중첩 타이머 이후엔 대기 시간을 최소 4밀리초 이상으로 강제해야 한다."라는 제약이 명시되어있습니다.
=======
````smart header="Zero delay is in fact not zero (in a browser)"
In the browser, there's a limitation of how often nested timers can run. The [HTML Living Standard](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers) says: "after five nested timers, the interval is forced to be at least 4 milliseconds.".
>>>>>>> upstream/master
````smart header="실제로 지연시간이 0인 경우는 없습니다(브라우저 환경)."
브라우저는 [HTML Living Standard](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers)에서 정한 중첩 타이머 실행 간격 관련 제약을 준수합니다. 해당 표준엔 "다섯 번째 중첩 타이머 이후엔 대기 시간을 최소 4밀리초 이상으로 강제해야 한다."라는 제약을 명시합니다.

예시를 보며 이 제약 사항을 이해해봅시다. 예시 내 `setTimeout`은 지연 없이 함수 run을 다시 호출할 수 있게 스케줄링 되어 있습니다. 배열 `times`에는 실제 지연 간격에 대한 정보가 기록되도록 해놓았는데, 배열 times에 어떤 값이 저장되는지 알아봅시다.

Expand All @@ -306,41 +281,22 @@ setTimeout(function run() {

이는 오래전부터 있던 제약인데, 구식 스크립트 중 일부는 아직 이 제약에 의존하는 경우가 있어서 명세서를 변경하지 못하고 있는 상황입니다.

<<<<<<< HEAD
한편, 서버 측엔 이런 제약이 없습니다. Node.js의 [process.nextTick](https://nodejs.org/api/process.html)과 [setImmediate](https://nodejs.org/api/timers.html)를 이용하면 비동기 작업을 지연 없이 실행할 수 있습니다. 위에서 언급된 제약은 브라우저에 한정됩니다.
=======
For server-side JavaScript, that limitation does not exist, and there exist other ways to schedule an immediate asynchronous job, like [setImmediate](https://nodejs.org/api/timers.html#timers_setimmediate_callback_args) for Node.js. So this note is browser-specific.
>>>>>>> upstream/master
한편, 서버 측엔 이런 제약이 없습니다. Node.js의 [setImmediate](https://nodejs.org/api/timers.html#timers_setimmediate_callback_args)와 같은 방법으로 비동기 작업을 즉시 실행할 수 있습니다. 위에서 언급된 제약은 브라우저에 한정합니다.
````

## 요약

<<<<<<< HEAD
- `setInterval(func, delay, ...args)`과 `setTimeout(func, delay, ...args)`은 `delay`밀리초 후에 `func`을 규칙적으로, 또는 한번 실행하도록 해줍니다.
- `setInterval·setTimeout`을 호출하고 반환받은 값을 `clearInterval·clearTimeout`에 넘겨주면 스케줄링을 취소할 수 있습니다.
- 중첩 `setTimeout`을 사용하면 `setInterval`을 사용한 것보다 유연하게 코드를 작성할 수 있습니다. 여기에 더하여 *지연 간격* 보장이라는 장점도 있습니다.
- `setTimeout·setInterval`을 호출하고 반환받은 값을 `clearTimeout·clearInterval`에 넘겨주면 스케줄링을 취소할 수 있습니다.
- 중첩 `setTimeout`을 사용하면 `setInterval`을 사용한 것보다 유연하게 코드를 작성할 수 있습니다. 여기에 더하여 실행 *사이의* 지연 간격을 더 정확하게 조절할 수 있게 해줍니다.
- 대기 시간이 0인 setTimeout(`setTimeout(func, 0)` 혹은 `setTimeout(func)`)을 사용하면 '현재 스크립트의 실행이 완료된 후 가능한 한 빠르게' 원하는 함수를 호출할 수 있습니다.
- 지연 없이 중첩 `setTimeout`을 5회 이상 호출하거나 지연 없는 `setInterval`에서 호출이 5회 이상 이뤄지면, 4밀리초 이상의 지연 간격이 강제로 더해집니다. 이는 브라우저에만 적용되는 사항이며, 하위 호환성을 위해 유지되고 있습니다.
=======
- Methods `setTimeout(func, delay, ...args)` and `setInterval(func, delay, ...args)` allow us to run the `func` once/regularly after `delay` milliseconds.
- To cancel the execution, we should call `clearTimeout/clearInterval` with the value returned by `setTimeout/setInterval`.
- Nested `setTimeout` calls are a more flexible alternative to `setInterval`, allowing us to set the time *between* executions more precisely.
- Zero delay scheduling with `setTimeout(func, 0)` (the same as `setTimeout(func)`) is used to schedule the call "as soon as possible, but after the current script is complete".
- The browser limits the minimal delay for five or more nested calls of `setTimeout` or for `setInterval` (after 5th call) to 4ms. That's for historical reasons.
>>>>>>> upstream/master

스케줄링 메서드를 사용할 땐 명시한 지연 간격이 *보장*되지 않을 수도 있다는 점에 유의해야 합니다.

<<<<<<< HEAD
아래와 같은 상황에서 브라우저 내 타이머가 느려지면 지연 간격이 보장되지 않습니다.
아래와 같은 여러 이유로 브라우저 내 타이머가 느려질 수 있습니다.
- CPU가 과부하 상태인 경우
- 브라우저 탭이 백그라운드 모드인 경우
- 노트북이 배터리에 의존해서 구동 중인 경우
=======
For example, the in-browser timer may slow down for a lot of reasons:
- The CPU is overloaded.
- The browser tab is in the background mode.
- The laptop is on battery saving mode.
>>>>>>> upstream/master
- 노트북이 배터리 절약 모드인 경우

이런 상황에서 타이머의 최소 지연 시간은 300밀리초에서 심하면 1,000밀리초까지 늘어납니다. 연장 시간은 브라우저나 구동 중인 운영 체제의 성능 설정에 따라 다릅니다.
36 changes: 7 additions & 29 deletions 1-js/06-advanced-functions/09-call-apply-decorators/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,11 @@ function cachingDecorator(func) {

slow = cachingDecorator(slow);

<<<<<<< HEAD
alert( slow(1) ); // slow(1)이 저장되었습니다.
alert( "다시 호출: " + slow(1) ); // 동일한 결과

alert( slow(2) ); // slow(2)가 저장되었습니다.
alert( "다시 호출: " + slow(2) ); // 윗줄과 동일한 결과
=======
alert( slow(1) ); // slow(1) is cached and the result returned
alert( "Again: " + slow(1) ); // slow(1) result returned from cache

alert( slow(2) ); // slow(2) is cached and the result returned
alert( "Again: " + slow(2) ); // slow(2) result returned from cache
>>>>>>> upstream/master
alert( slow(1) ); // slow(1)를 캐시에 저장하고 결과를 반환합니다.
alert( "다시 호출: " + slow(1) ); // 캐시에서 slow(1)의 결과를 가져옵니다.

alert( slow(2) ); // slow(2)를 캐시에 저장하고 결과를 반환합니다.
alert( "다시 호출: " + slow(2) ); // 캐시에서 slow(2)의 결과를 가져옵니다.
```

`cachingDecorator`같이 인수로 받은 함수의 행동을 변경시켜주는 함수를 *데코레이터(decorator)* 라고 부릅니다.
Expand Down Expand Up @@ -309,32 +301,18 @@ func.apply(context, args)
따라서 아래 코드 두 줄은 거의 같은 역할을 합니다.

```js
<<<<<<< HEAD
func.call(context, ...args); // 전개 구문을 사용해 인수가 담긴 배열을 전달하는 것과
func.apply(context, args); // call을 사용하는 것은 동일합니다.
```

그런데 약간의 차이가 있긴 합니다.
=======
func.call(context, ...args);
func.apply(context, args);
```

They perform the same call of `func` with given context and arguments.
위 코드는 `func`을 동일한 컨텍스트와 인수로 호출합니다.

There's only a subtle difference regarding `args`:
>>>>>>> upstream/master
그런데 `args`에 관해 약간의 차이가 있긴 합니다.

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

<<<<<<< HEAD
이 차이만 빼면 두 메서드는 완전히 동일하게 동작합니다. 인수가 이터러블 형태라면 `call`을, 유사 배열 형태라면 `apply`를 사용하면 됩니다.

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

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

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@

<<<<<<< HEAD
에러는 `ask`가 함수 `loginOk`, `loginFail`을 객체 없이 가지고 오기 때문에 발생합니다.
=======
The error occurs because `askPassword` gets functions `loginOk/loginFail` without the object.
>>>>>>> upstream/master
에러는 `askPassword`가 함수 `loginOk`, `loginFail`을 객체 없이 가지고 오기 때문에 발생합니다.

ask는 `loginOk`, `loginFail`을 호출할 때 `this=undefined`라고 자연스레 가정합니다.

Expand Down
27 changes: 5 additions & 22 deletions 1-js/06-advanced-functions/10-bind/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,7 @@ funcUser(); // John
*/!*
```

<<<<<<< HEAD
여기서 `func.bind(user)`는 `func`의 `this`를 `user`로 '바인딩한 변형'이라고 생각하시면 됩니다.
=======
Here `func.bind(user)` is a "bound variant" of `func`, with fixed `this=user`.
>>>>>>> upstream/master
여기서 `func.bind(user)`는 `this=user`로 고정된 `func`의 '바인딩한 변형'이라고 생각하면 됩니다.

인수는 원본 함수 `func`에 '그대로' 전달됩니다.

Expand Down Expand Up @@ -189,13 +185,8 @@ let user = {

let say = user.say.bind(user);

<<<<<<< HEAD
say("Hello"); // Hello, John (인수 "Hello"가 say로 전달되었습니다.)
say("Bye"); // Bye, John ("Bye"가 say로 전달되었습니다.)
=======
say("Hello"); // Hello, John! ("Hello" argument is passed to say)
say("Bye"); // Bye, John! ("Bye" is passed to say)
>>>>>>> upstream/master
say("Hello"); // Hello, John! (인수 "Hello"를 say에 전달합니다.)
say("Bye"); // Bye, John! ("Bye"를 say에 전달합니다.)
```

````smart header="`bindAll`로 메서드 전체 바인딩하기"
Expand All @@ -209,11 +200,7 @@ for (let key in user) {
}
```

<<<<<<< HEAD
자바스크립트 라이브러리를 사용해도 대규모 바인딩을 할 수 있습니다. lodash 라이브러리의 [_.bindAll(object, methodNames)](http://lodash.com/docs#bindAll)이 그 예입니다.
=======
JavaScript libraries also provide functions for convenient mass binding , e.g. [_.bindAll(object, methodNames)](https://lodash.com/docs#bindAll) in lodash.
>>>>>>> upstream/master
자바스크립트 라이브러리를 사용해도 대규모 바인딩을 할 수 있습니다. lodash 라이브러리의 [_.bindAll(object, methodNames)](https://lodash.com/docs#bindAll)이 그 예입니다.
````

## 부분 적용
Expand Down Expand Up @@ -258,11 +245,7 @@ alert( double(5) ); // = mul(2, 5) = 10

이런 방식을 [부분 적용(partial application)](https://en.wikipedia.org/wiki/Partial_application)이라고 부릅니다. 부분 적용을 사용하면 기존 함수의 매개변수를 고정하여 새로운 함수를 만들 수 있습니다.

<<<<<<< HEAD
위 예시에선 `this`를 사용하지 않았다는 점에 주목하시기 바랍니다. `bind`엔 컨텍스트를 항상 넘겨줘야 하므로 `null`을 사용했습니다.
=======
Please note that we actually don't use `this` here. But `bind` requires it, so we must put in something like `null`.
>>>>>>> upstream/master
위 예시에선 `this`를 사용하지 않았다는 점에 주목합니다. 그런데 `bind`는 컨텍스트가 필요하므로 `null` 같은 값을 넣어줘야 합니다.

부분 적용을 사용해 3을 곱해주는 함수 `triple`을 만들어보겠습니다.

Expand Down
5 changes: 0 additions & 5 deletions 1-js/06-advanced-functions/12-arrow-functions/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,8 @@ let group = {
showList() {
*!*
this.students.forEach(function(student) {
<<<<<<< HEAD
// TypeError: Cannot read property 'title' of undefined
alert(this.title + ': ' + student)
=======
// Error: Cannot read property 'title' of undefined
alert(this.title + ': ' + student);
>>>>>>> upstream/master
});
*/!*
}
Expand Down
Loading