From 70702321f5dd403ba1e761576566aaac357fd64b Mon Sep 17 00:00:00 2001 From: Chris-D-Lee Date: Wed, 18 Sep 2019 11:20:01 +1000 Subject: [PATCH 1/2] =?UTF-8?q?[=EB=8D=B0=EC=BD=94=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=ED=84=B0]=EB=A6=AC=EB=B7=B0=EB=82=B4=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [데코레이터] 원문변경에 따른 재작업 Update 1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/02-delay/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/02-delay/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/02-delay/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/02-delay/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> Update 1-js/06-advanced-functions/09-call-apply-decorators/article.md Co-Authored-By: Ju Yeong <33684401+JuYeong0413@users.noreply.github.com> --- .../01-spy-decorator/solution.md | 2 +- .../01-spy-decorator/task.md | 12 +- .../02-delay/solution.md | 14 +- .../09-call-apply-decorators/02-delay/task.md | 16 +- .../03-debounce/solution.md | 12 +- .../03-debounce/task.md | 18 +- .../04-throttle/solution.md | 10 +- .../04-throttle/task.md | 44 +-- .../09-call-apply-decorators/article.md | 257 +++++++++--------- 9 files changed, 190 insertions(+), 195 deletions(-) diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md index 0c8a211b49..0838024fa3 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md @@ -1 +1 @@ -The wrapper returned by `spy(f)` should store all arguments and then use `f.apply` to forward the call. +`spy(f)`에 의해 반환된 래퍼는 모든 인수를 저장한 다음 `f.apply`를 사용하여 호출을 전달해야 합니다. diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md index a3843107c9..5560ec7bab 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md @@ -2,17 +2,17 @@ importance: 5 --- -# Spy decorator +# 스파이 데코레이터 -Create a decorator `spy(func)` that should return a wrapper that saves all calls to function in its `calls` property. +`calls` 프로퍼티에 함수에 대한 모든 호출을 저장한 래퍼를 반환하는 데코레이터 `spy(func)`를 만들어 보세요. -Every call is saved as an array of arguments. +모든 호출은 인수 배열로 저장되어야 합니다. -For instance: +예를 들면 ```js function work(a, b) { - alert( a + b ); // work is an arbitrary function or method + alert( a + b ); // work 함수는 임의의 함수거나 메서드 입니다. } *!* @@ -27,4 +27,4 @@ for (let args of work.calls) { } ``` -P.S. That decorator is sometimes useful for unit-testing. Its advanced form is `sinon.spy` in [Sinon.JS](http://sinonjs.org/) library. +P.S. 이러한 데코레이터는 때때로 단위 테스트에 유용합니다. 고급적인 형식은 [Sinon.JS](http://sinonjs.org/) 라이브러리에 있는 `sinon.spy`가 있습니다. diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md index 24bb4d4484..a87324d0ef 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md @@ -1,4 +1,4 @@ -The solution: +해답 ```js run demo function delay(f, ms) { @@ -11,22 +11,22 @@ function delay(f, ms) { let f1000 = delay(alert, 1000); -f1000("test"); // shows "test" after 1000ms +f1000("test"); // 1000 밀리초 후에 "test"를 보여줌 ``` -Please note how an arrow function is used here. As we know, arrow functions do not have own `this` and `arguments`, so `f.apply(this, arguments)` takes `this` and `arguments` from the wrapper. +위의 답안에서 어떻게 화살표 함수가 사용되었는지 주목하세요. 이미 살펴보았듯이 화살표 함수는 자체적으로 `this`와 `arguments`가 없습니다. 그래서 `f.apply(this, arguments)`는 `this`와 `arguments`를 래퍼로부터 가져올 수 있는 것이죠. -If we pass a regular function, `setTimeout` would call it without arguments and `this=window` (assuming we're in the browser). +일반 함수로 전달했다면 `setTimeout`은 인수가 없고 `this=window`로 호출되었을 것입니다(브라우저 안이라고 가정해서). -We still can pass the right `this` by using an intermediate variable, but that's a little bit more cumbersome: +일반 함수를 사용해도 여전히 중간 변수를 사용하여 올바른 `this`를 전달할 수 있지만 조금 더 신경써야할 부분이 많습니다. ```js function delay(f, ms) { return function(...args) { - let savedThis = this; // store this into an intermediate variable + let savedThis = this; // this를 중간 변수로 저장합니다. setTimeout(function() { - f.apply(savedThis, args); // use it here + f.apply(savedThis, args); // 여기서 중간 변수로 저장된 this를 사용합니다. }, ms); }; diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/task.md index c04c68d7ef..9a13fbfdd7 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/task.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/task.md @@ -2,25 +2,25 @@ importance: 5 --- -# Delaying decorator +# 지연 데코레이터 -Create a decorator `delay(f, ms)` that delays each call of `f` by `ms` milliseconds. +`delay(f, ms)`라는 각각의 `f` 호출을 `ms` 밀리초 만큼 지연하는 데코레이터를 작성해보세요. -For instance: +예를 들면 ```js function f(x) { alert(x); } -// create wrappers +// 래퍼를 생성합니다. let f1000 = delay(f, 1000); let f1500 = delay(f, 1500); -f1000("test"); // shows "test" after 1000ms -f1500("test"); // shows "test" after 1500ms +f1000("test"); // 1000 밀리초 후에 "test"를 보여줍니다. +f1500("test"); // 1500 밀리초 후에 "test"를 보여줍니다. ``` -In other words, `delay(f, ms)` returns a "delayed by `ms`" variant of `f`. +다르게 표현하면, `delay(f, ms)` 함수는 `f`함수를 `ms`만큼 지연된 변형된 형태로 반환합니다. -In the code above, `f` is a function of a single argument, but your solution should pass all arguments and the context `this`. +위의 코드에서 `f`는 단일 인수의 함수이지만 솔루션은 모든 인수와 컨텍스트 `this`를 전달해야 합니다. diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md index 4f5867ded9..7c0047dda5 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md @@ -16,13 +16,13 @@ function debounce(f, ms) { } ``` -A call to `debounce` returns a wrapper. There may be two states: +`debounce`를 호출하면 래퍼를 반환합니다. 여기에는 두 가지 상태가 있습니다. -- `isCooldown = false` -- ready to run. -- `isCooldown = true` -- waiting for the timeout. +- `isCooldown = false` -- 실행시킬 준비가 되었습니다. +- `isCooldown = true` -- 시간이 지날동안 기다립니다. -In the first call `isCooldown` is falsy, so the call proceeds, and the state changes to `true`. +첫번째 `isCoolDown`은 허위로 호출됩니다. 그래서 호출이 되면 상태는 `true`로 바뀌는 것이죠. -While `isCooldown` is true, all other calls are ignored. +`isCooldown`이 true일 동안은 다른 호출은 무시됩니다. -Then `setTimeout` reverts it to `false` after the given delay. +그리고 `setTimeout` 함수가 주어진 지연시간이 지난 후에 상태를 `false`로 바꾸게 됩니다. diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md index 2620f1c712..74a4ff31d8 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md @@ -2,23 +2,23 @@ importance: 5 --- -# Debounce decorator +# 디바운스 데코레이터 -The result of `debounce(f, ms)` decorator should be a wrapper that passes the call to `f` at maximum once per `ms` milliseconds. +`debounce(f, ms)`데코레이터는 `ms`밀리초 마다 최대값에 한번 `f` 에 호출을 전달하는 래퍼이어야 합니다. -In other words, when we call a "debounced" function, it guarantees that all future calls to the function made less than `ms` milliseconds after the previous call will be ignored. +다르게 표현하면 "debounced" 함수를 호출하면 `ms` 밀리초 미만의 함수에 대한 다른 함수 호출은 이전 함수 호출 후 무시되어야 합니다. -For instance: +예를 들면 ```js no-beautify let f = debounce(alert, 1000); -f(1); // runs immediately -f(2); // ignored +f(1); // 바로 실행됩니다. +f(2); // 무시됩니다. -setTimeout( () => f(3), 100); // ignored ( only 100 ms passed ) -setTimeout( () => f(4), 1100); // runs -setTimeout( () => f(5), 1500); // ignored (less than 1000 ms from the last run) +setTimeout( () => f(3), 100); // 무시됨 ( 오직 100 만 전달됨 ) +setTimeout( () => f(4), 1100); // 실행됨 +setTimeout( () => f(5), 1500); // 무시됨 (마지막 실행 후에 1000ms 가 지나지 않았음) ``` In practice `debounce` is useful for functions that retrieve/update something when we know that nothing new can be done in such a short period of time, so it's better not to waste resources. diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md index c844016d3b..1b44b8b358 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md @@ -30,10 +30,10 @@ function throttle(func, ms) { } ``` -A call to `throttle(func, ms)` returns `wrapper`. +`throttle(func, ms)`에 대한 호출은`wrapper`를 반환합니다. -1. During the first call, the `wrapper` just runs `func` and sets the cooldown state (`isThrottled = true`). -2. In this state all calls memorized in `savedArgs/savedThis`. Please note that both the context and the arguments are equally important and should be memorized. We need them simultaneously to reproduce the call. -3. ...Then after `ms` milliseconds pass, `setTimeout` triggers. The cooldown state is removed (`isThrottled = false`). And if we had ignored calls, then `wrapper` is executed with last memorized arguments and context. +1. 첫 번째 호출 중에 `wrapper`는 `func`를 실행하고 cooldown의 상태를 설정합니다(`isThrottled = true`). +2. 상태가 설정되고 모든 호출은 `savedArgs/savedThis`에 기억됩니다. 컨텍스트와 인수는 똑같이 중요하며 기억돼야 합니다. 호출을 재현하기 위해 컨텍스트와 인수가 동시에 필요합니다. +3. ...`ms` 밀리초가 지나면 `setTimeout`이 트리거 되고 cooldown의 상태는 제거됩니다(`isThrottled = false`). 그리고 호출이 무시된다면 `wrapper`는 마지막에 기억된 컨텍스트와 인수와 함께 실행됩니다. -The 3rd step runs not `func`, but `wrapper`, because we not only need to execute `func`, but once again enter the cooldown state and setup the timeout to reset it. +3번째 단계는 `func`가 아니라 `wrapper`로 실행됩니다. 왜냐하면 `func`만을 실행하는 것이 아니라 cooldown 상태를 입력하고 timeout을 설정해서 cooldown을 리셋할 수 있게 해야 되기 때문입니다. diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md index 567c9ce7a1..6c9308d1d8 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md @@ -2,47 +2,47 @@ importance: 5 --- -# Throttle decorator +# Throttle 데코레이터 -Create a "throttling" decorator `throttle(f, ms)` -- that returns a wrapper, passing the call to `f` at maximum once per `ms` milliseconds. Those calls that fall into the "cooldown" period, are ignored. +"throttling" 데코레이터라는 `ms` 밀리초가 지난 후 호출을 `f`로 보내는 래퍼를 반환하는 `throttle(f, ms)`를 만들어 봅시다. "cooldown" 시간이 지나면 호출은 무시될 것입니다. -**The difference with `debounce` -- if an ignored call is the last during the cooldown, then it executes at the end of the delay.** +**`debounce`와의 차이점은 cooldown 중에 무시된 호출이 마지막이면 지연이 끝날 때 실행됩니다.** -Let's check the real-life application to better understand that requirement and to see where it comes from. +실제 응용 프로그램을 확인하여 해당 요구 사항을 더 잘 이해하고 어디에서 왔는지 확인합시다. -**For instance, we want to track mouse movements.** +**예를 들어 마우스 움직임을 추적하려고 합니다.** -In browser we can setup a function to run at every mouse movement and get the pointer location as it moves. During an active mouse usage, this function usually runs very frequently, can be something like 100 times per second (every 10 ms). +브라우저에서 우리는 모든 마우스 움직임에서 실행되고 포인터가 움직일 때 포인터 위치를 얻는 기능을 설정할 수 있습니다. 마우스를 사용하는 동안 이 기능은 일반적으로 매우 자주 실행되며 초당 100회 (매 10ms) 정도일 수 있습니다. -**We'd like to update some information on the web-page when the pointer moves.** +**포인터가 움직일 때 웹 페이지의 일부 정보를 업데이트하려고 합니다.** -...But updating function `update()` is too heavy to do it on every micro-movement. There is also no sense in updating more often than once per 100ms. +...그런데 `update()`라는 함수가 미세한 움직임에 매번 업데이트하기에는 너무 무거워 보입니다. 100ms에 한번 보다 더 업데이트하는 건 무의미해 보입니다. -So we'll wrap it into the decorator: use `throttle(update, 100)` as the function to run on each mouse move instead of the original `update()`. The decorator will be called often, but forward the call to `update()` at maximum once per 100ms. +그래서 원래의 `update()` 함수 대신에 매번 마우스를 움직일 때마다 동작하는 `throttle(update, 100)` 데코레이터를 `update()` 함수에 적용해보겠습니다. 이 데코레이터는 자주 호출되지만 `update()`로의 호출 전달을 최대 100ms에 한 번만 하게 될 것입니다. -Visually, it will look like this: +시각적으로 다음과 같습니다. -1. For the first mouse movement the decorated variant immediately passes the call to `update`. That's important, the user sees our reaction to their move immediately. -2. Then as the mouse moves on, until `100ms` nothing happens. The decorated variant ignores calls. -3. At the end of `100ms` -- one more `update` happens with the last coordinates. -4. Then, finally, the mouse stops somewhere. The decorated variant waits until `100ms` expire and then runs `update` with last coordinates. So, quite important, the final mouse coordinates are processed. +1. 첫 번째 마우스 이동의 경우 데코레이터 함수는 즉시 `update` 호출을 전달합니다. 중요한 것은 사용자가 자신의 움직임에 대한 반응을 즉시 볼 수 있다는 것입니다. +2. 마우스가 움직일 때 `100ms`까지 아무 일도 일어나지 않습니다. 데코레이터 함수는 호출을 무시합니다. +3. `100ms`의 마지막에서 마지막 좌표로 `update`함수 호출이 한번더 발생합니다. +4. 마지막으로 마우스가 어딘가에서 멈춥니다. 데코레이터 함수는 `100ms`가 지날 때까지 기다렸다가 마지막 좌표로 `update` 함수를 실행합니다. 그리고 마지막으로 최종 마우스 좌표가 처리됩니다. -A code example: +코드 예시 ```js function f(a) { console.log(a) }; -// f1000 passes calls to f at maximum once per 1000 ms +// f1000 함수는 f함수에 호출을 최대 1000ms에 한번 전달합니다. let f1000 = throttle(f, 1000); -f1000(1); // shows 1 -f1000(2); // (throttling, 1000ms not out yet) -f1000(3); // (throttling, 1000ms not out yet) +f1000(1); // 1을 보여줍니다. +f1000(2); // (throttling, 1000ms 가 아직 아닙니다.) +f1000(3); // (throttling, 1000ms 가 아직 아닙니다.) -// when 1000 ms time out... -// ...outputs 3, intermediate value 2 was ignored +// 1000 ms 가 지나면... +// ...3을 출력하고, 중간값 2는 무시될 것입니다. ``` -P.S. Arguments and the context `this` passed to `f1000` should be passed to the original `f`. +P.S. `f1000`함수로 전달되는 인수와 컨텍스트 `this`는 원래의 `f`함수로 전달되어야 합니다. diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/article.md b/1-js/06-advanced-functions/09-call-apply-decorators/article.md index 8536cf3142..6b988ad9b2 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/article.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/article.md @@ -1,20 +1,20 @@ -# Decorators and forwarding, call/apply +# 데코레이터 그리고 포워딩, call/apply -JavaScript gives exceptional flexibility when dealing with functions. They can be passed around, used as objects, and now we'll see how to *forward* calls between them and *decorate* them. +자바스크립트는 함수들을 대할 때 특별한 유동성을 제공합니다. 함수들이 서로 전달될 수 있고 객체처럼 사용될 수 있습니다. 이번 챕터에서는 여기서 더 나아가 함수들이 어떻게 *포워드* 되고 *데코레이트(decorate)* 되는지 살펴보겠습니다. -## Transparent caching +## 캐싱의 투명성(Transparent caching) -Let's say we have a function `slow(x)` which is CPU-heavy, but its results are stable. In other words, for the same `x` it always returns the same result. +`slow(x)`라는 CPU 사용률이 무겁지만, 결과는 안정적인 함수가 있다고 가정해보죠. 다르게 표현한다면, 똑같은 `x`라는 값에 대해 항상 같은 결과를 반환하는 함수가 있다고 가정해 보겠습니다. -If the function is called often, we may want to cache (remember) the results to avoid spending extra-time on recalculations. +만약에 이러한 함수가 자주 호출된다면, 다른 `x`의 결과들을 캐시(기억) 해서 다시 계산하는 데 소모되는 추가적인 시간을 줄이고 싶을 것입니다. -But instead of adding that functionality into `slow()` we'll create a wrapper function, that adds caching. As we'll see, there are many benefits of doing so. +그런데 이런 방법을 구현할 때 `slow()`에 추가적인 기능을 더하는 대신 래퍼(wrapper)를 생성할 수 있습니다. 이렇게 하는 데는 많은 장점이 있습니다. -Here's the code, and explanations follow: +아래에 코드와 설명을 통해 알아보겠습니다. ```js run function slow(x) { - // there can be a heavy CPU-intensive job here + // CPU를 많이 사용하는 작업이 있다고 합시다. alert(`Called with ${x}`); return x; } @@ -23,65 +23,66 @@ function cachingDecorator(func) { let cache = new Map(); return function(x) { - if (cache.has(x)) { // if there's such key in cache - return cache.get(x); // read the result from it + if (cache.has(x)) { // 만약에 결과가 map에 담겨져 온다면 + return cache.get(x); // 그것을 반환합니다. } - let result = func(x); // otherwise call func + let result = func(x); // 아닐 경우 함수를 호출합니다. - cache.set(x, result); // and cache (remember) the result + cache.set(x, result); // 그리고 결과를 캐시(기억) 합니다. return result; }; } slow = cachingDecorator(slow); -alert( slow(1) ); // slow(1) is cached -alert( "Again: " + slow(1) ); // the same +alert( slow(1) ); // slow(1)이 캐시되어 있습니다. +alert( "Again: " + slow(1) ); // 똑같습니다. -alert( slow(2) ); // slow(2) is cached -alert( "Again: " + slow(2) ); // the same as the previous line +alert( slow(2) ); // slow(2)가 캐시되어 있습니다. +alert( "Again: " + slow(2) ); // 이전 라인과 같습니다. ``` -In the code above `cachingDecorator` is a *decorator*: a special function that takes another function and alters its behavior. +위의 `cachingDecorator` 예시처럼 다른 함수를 가져와서 그 행동을 변환하는 특별한 함수를 바로 *데코레이터* 라고 합니다. -The idea is that we can call `cachingDecorator` for any function, and it will return the caching wrapper. That's great, because we can have many functions that could use such a feature, and all we need to do is to apply `cachingDecorator` to them. +중요한 것은 `cachingDecorator`는 대상이 어떤 함수이든지 상관없이 호출할 수 있고 그 함수는 캐싱 래퍼를 반환할 것입니다. 이런 방법은 어떠한 함수도 특별한 기능처럼 사용할 수 있기 때문에 좋습니다. 오직 필요한 것은 `cachingDecorator`를 적용하는 것뿐입니다. -By separating caching from the main function code we also keep the main code simpler. +캐싱을 해당하는 메인 함수 코드로부터 분리하는 것은 메인 코드를 간단하게 하는 데도 도움이 됩니다. -The result of `cachingDecorator(func)` is a "wrapper": `function(x)` that "wraps" the call of `func(x)` into caching logic: +`cachingDecorator(func)`의 결괏값은 "래퍼" 입니다. `function(x)` 이라는 함수로 "둘러싼" `func(x)`의 호출을 caching 로직으로 담아냅니다. ![](decorator-makecaching-wrapper.svg) -From an outside code, the wrapped `slow` function still does the same. It just got a caching aspect added to its behavior. +위의 그림처럼, 래퍼는 `func(x)`의 결괏값을 "있는 그대로" 반환합니다. 코드의 바깥에서는, 둘러싸여진 `slow` 함수가 아직 똑같은 작업을 합니다. 단지 그 행동에 캐싱하는 것이 더해졌을 뿐이죠. -To summarize, there are several benefits of using a separate `cachingDecorator` instead of altering the code of `slow` itself: +다시 설명하면, `slow` 코드를 직접 수정하는 것보다 독립적인 `cachingDecorator`를 사용하는 것은 다음과 같은 많은 이점이 있습니다. -- The `cachingDecorator` is reusable. We can apply it to another function. -- The caching logic is separate, it did not increase the complexity of `slow` itself (if there was any). -- We can combine multiple decorators if needed (other decorators will follow). +- `cachingDecorator`는 재사용 가능합니다. 다른 함수에도 적용할 수 있습니다. +- 캐싱하는 로직이 분리됩니다. `slow` 함수 (다른 함수들이 되더라도) 자체를 복잡하게 만들지 않습니다. +- 필요에 따라 여러 개의 데코레이터를 섞어서 사용할 수 있습니다.(다른 데코레이터에 대해서는 곧 알아보겠습니다.) -## Using "func.call" for the context -The caching decorator mentioned above is not suited to work with object methods. +## "func.call"을 컨텍스트에 사용하기 -For instance, in the code below `worker.slow()` stops working after the decoration: +위에서 언급한 캐싱 데코레이터는 객체 메서드와 사용하기엔 적합하지 않습니다. + +예를 들면, 아래의 `worker.slow()` 코드는 데코레이션 뒤에 작동을 멈춥니다. ```js run -// we'll make worker.slow caching +// worker.slow 캐싱을 만듦 let worker = { someMethod() { return 1; }, slow(x) { - // actually, there can be a scary CPU-heavy task here + // 아래와 같은 CPU-heavy 작업들이 있다고 한다면 alert("Called with " + x); return x * this.someMethod(); // (*) } }; -// same code as before +// 이전 코드와 같음 function cachingDecorator(func) { let cache = new Map(); return function(x) { @@ -96,49 +97,49 @@ function cachingDecorator(func) { }; } -alert( worker.slow(1) ); // the original method works +alert( worker.slow(1) ); // 원래 메서드는 작동함 -worker.slow = cachingDecorator(worker.slow); // now make it caching +worker.slow = cachingDecorator(worker.slow); // 캐싱을 생성 *!* -alert( worker.slow(2) ); // Whoops! Error: Cannot read property 'someMethod' of undefined +alert( worker.slow(2) ); // 에러, 정의되지 않은 'someMethod'프로퍼티를 읽을 수 없음 */!* ``` -The error occurs in the line `(*)` that tries to access `this.someMethod` and fails. Can you see why? +`(*)`줄의 `this.someMethod`를 접근하려고 하면 에러가 발생하고 실패합니다. 왜 그럴까요? -The reason is that the wrapper calls the original function as `func(x)` in the line `(**)`. And, when called like that, the function gets `this = undefined`. +이유는 `(**)`라인에서 래퍼는 원래의 함수인 `func(x)`를 그대로 호출하려고 하고 그렇게 호출되면 `this = undefined`가 되기 때문입니다. -We would observe a similar symptom if we tried to run: +아래의 코드를 실행시킬 경우 비슷한 현상이 일어납니다. ```js let func = worker.slow; func(2); ``` -So, the wrapper passes the call to the original method, but without the context `this`. Hence the error. +래퍼는 컨텍스트에 있는 `this` 없이 원래 가지고 있던 메서드를 호출하기 때문에 에러가 발생합니다. -Let's fix it. +이제 이런 문제를 고쳐보겠습니다. -There's a special built-in function method [func.call(context, ...args)](mdn:js/Function/call) that allows to call a function explicitly setting `this`. +특별히 제작된 함수 메서드인 [func.call(context, ...args)](mdn:js/Function/call)를 사용하면 함수를 호출할 때 `this`를 설정하게 허용하고 있습니다. -The syntax is: +문법은 다음과 같습니다. ```js func.call(context, arg1, arg2, ...) ``` -It runs `func` providing the first argument as `this`, and the next as the arguments. +`func`를 실행할 때 첫 번째 인수로 `this`를 사용합니다. 그리고 다음 인수들이 따라옵니다. -To put it simply, these two calls do almost the same: +아래의 두 호출은 거의 같습니다. ```js func(1, 2, 3); func.call(obj, 1, 2, 3) ``` -They both call `func` with arguments `1`, `2` and `3`. The only difference is that `func.call` also sets `this` to `obj`. +위의 두 경우 모두 `func`와 인수들인 `1`, `2` 그리고 `3`을 호출합니다. 다른 점이 있다면 `func.call`이 `this`를 `obj`로 설정한다는 것이죠. -As an example, in the code below we call `sayHi` in the context of different objects: `sayHi.call(user)` runs `sayHi` providing `this=user`, and the next line sets `this=admin`: +예시에서처럼, 아래의 코드는 `sayHi`를 다른 객체들의 컨텍스트에서 호출합니다. `sayHi.call(user)`는 `this=user`로 설정된 `sayHi`를 실행하고 다음 라인은 `this=admin`으로 설정합니다. ```js run function sayHi() { @@ -148,12 +149,12 @@ function sayHi() { let user = { name: "John" }; let admin = { name: "Admin" }; -// use call to pass different objects as "this" +// 다른 객체를 "this"로 설정하도록 호출함 sayHi.call( user ); // this = John sayHi.call( admin ); // this = Admin ``` -And here we use `call` to call `say` with the given context and phrase: +그리고 아래 예시처럼 `call`을 사용해서 `say`를 부여받은 컨텍스트와 phrase를 호출합니다. ```js run @@ -163,11 +164,13 @@ function say(phrase) { let user = { name: "John" }; -// user becomes this, and "Hello" becomes the first argument +// user는 this가 되고, "Hello"는 첫 번째 인수가 됩니다. say.call( user, "Hello" ); // John: Hello ``` -In our case, we can use `call` in the wrapper to pass the context to the original function: + +아래 예시에서는, `call`을 래퍼 안에서 사용해서 원래의 함수에 컨텍스트를 전달합니다. + ```js run let worker = { @@ -188,57 +191,57 @@ function cachingDecorator(func) { return cache.get(x); } *!* - let result = func.call(this, x); // "this" is passed correctly now + let result = func.call(this, x); // "this"가 정확히 전달되었음 */!* cache.set(x, result); return result; }; } -worker.slow = cachingDecorator(worker.slow); // now make it caching +worker.slow = cachingDecorator(worker.slow); // 캐시를 생성합니다. -alert( worker.slow(2) ); // works -alert( worker.slow(2) ); // works, doesn't call the original (cached) +alert( worker.slow(2) ); // 작동함 +alert( worker.slow(2) ); // 작동함, 원래함수를 호출하지는 않았음(캐싱되었음) ``` -Now everything is fine. +이제 모두 제대로 작동하는 것 같습니다. -To make it all clear, let's see more deeply how `this` is passed along: +더 확실히 이해하기 위해서 `this`가 어떻게 전달되었는지 자세히 알아보겠습니다. -1. After the decoration `worker.slow` is now the wrapper `function (x) { ... }`. -2. So when `worker.slow(2)` is executed, the wrapper gets `2` as an argument and `this=worker` (it's the object before dot). -3. Inside the wrapper, assuming the result is not yet cached, `func.call(this, x)` passes the current `this` (`=worker`) and the current argument (`=2`) to the original method. +1. `worker.slow`를 데코레이션 한 후에 `function (x) { ... }` 가 래퍼가 되었습니다. +2. 그래서 `worker.slow(2)`가 실행되었을 때는, 래퍼가 `2`를 인수로 받아 `this=worker`가 됩니다.(마침표 이전에 객체입니다.) +3. wrapper 안에서는, 결과가 캐시 되지 않았다고 가정합니다. `func.call(this, x)`이 현재의 `this` (`=worker`)를 전달하고 현재의 인수 (`=2`)를 원래 메서드에 전달합니다. -## Going multi-argument with "func.apply" +## "func.apply"를 다중-인수와 사용하기 -Now let's make `cachingDecorator` even more universal. Till now it was working only with single-argument functions. +이제 `cachingDecorator`를 다목적으로 만들어 보겠습니다. 아직은 오직 하나의 인수를 가진 함수들과 작동했으니까요. -Now how to cache the multi-argument `worker.slow` method? +`worker.slow` 메서드를 어떻게 하면 다중-인수를 캐싱하게 할 수 있을까요? ```js let worker = { slow(min, max) { - return min + max; // scary CPU-hogger is assumed + return min + max; // CPU를 많이 잡아먹는 작업이라고 가정합니다. } }; -// should remember same-argument calls +// 똑같은 인수들을 호출해야 할 것입니다. worker.slow = cachingDecorator(worker.slow); ``` -Previously, for a single argument `x` we could just `cache.set(x, result)` to save the result and `cache.get(x)` to retrieve it. But now we need to remember the result for a *combination of arguments* `(min,max)`. The native `Map` takes single value only as the key. +첫 번째는 어떻게 `min`과 `max` 두 인수를 `cache` 맵의 키로 사용할 것인가입니다. 한가지 인수를 사용할 때 `x`는 `cache.set(x, result)`을 사용해서 결과를 저장하고 `cache.get(x)`을 사용해 결과를 찾아왔습니다. 그러나 이제 *인수의 조합* `(min,max)`를 기억해야 합니다. 네이티브 `Map`은 오직 한가지 값을 키로 가질 수 있습니다. -There are many solutions possible: +이것을 해결하는 방법은 여러 가지가 있습니다. -1. Implement a new (or use a third-party) map-like data structure that is more versatile and allows multi-keys. -2. Use nested maps: `cache.set(min)` will be a `Map` that stores the pair `(max, result)`. So we can get `result` as `cache.get(min).get(max)`. -3. Join two values into one. In our particular case we can just use a string `"min,max"` as the `Map` key. For flexibility, we can allow to provide a *hashing function* for the decorator, that knows how to make one value from many. +1. 새로운 (또는 서드파티) 더욱 변형하기 쉽고 멀티 키를 사용할 수 있는 자료형을 가진 맵을 사용합니다. +2. 중첩 맵을 사용합니다. `cache.set(min)`은 `(max, result)`라는 짝을 저장하는 `Map`이 될 것입니다. 그렇게 하면 `result`를 `cache.get(min).get(max)`와 같은 방법으로 얻을 수 있을 것입니다. +3. 두 가지 값을 하나로 합칩니다. `"min,max"` 문자열을 그냥 `Map` 값으로 사용할 것입니다. 좀 더 유동적으로 하기 위해서 *hashing function*을 데코레이터에 사용한다면 어떻게 많은 값을 하나로 만들 수 있는지 알 수 있습니다. -For many practical applications, the 3rd variant is good enough, so we'll stick to it. +대다수의 애플리케이션은 3번째 방법이 적절하기 때문에 여기에서도 첫 번째 문제를 해결할 방법으로 선택하도록 하겠습니다. -Also we need to replace `func.call(this, x)` with `func.call(this, ...arguments)`, to pass all arguments to the wrapped function call, not just the first one. +또한 `func.call(this, x)`을 `func.call(this, ...arguments)`으로 대체해서 첫 번째 인수만이 아니라 전달된 모든 인수를 래핑 된 함수 호출에 전달해야 합니다. -Here's a more powerful `cachingDecorator`: +`cachingDecorator`를 통해서 위에서 언급한 모든 것을 살펴보겠습니다. ```js run let worker = { @@ -273,48 +276,48 @@ function hash(args) { worker.slow = cachingDecorator(worker.slow, hash); -alert( worker.slow(3, 5) ); // works -alert( "Again " + worker.slow(3, 5) ); // same (cached) +alert( worker.slow(3, 5) ); // 작동함 +alert( "Again " + worker.slow(3, 5) ); // 똑같음(캐시에 저장됨) ``` -Now it works with any number of arguments (though the hash function would also need to be adjusted to allow any number of arguments. An interesting way to handle this will be covered below). +이제 래퍼는 인수의 개수가 몇 개든지 작동하게 되었습니다. -There are two changes: +위의 예시에는 두 가지 변경 점이 있습니다. -- In the line `(*)` it calls `hash` to create a single key from `arguments`. Here we use a simple "joining" function that turns arguments `(3, 5)` into the key `"3,5"`. More complex cases may require other hashing functions. -- Then `(**)` uses `func.call(this, ...arguments)` to pass both the context and all arguments the wrapper got (not just the first one) to the original function. +- `(*)`있는 줄에서 `hash`를 호출해서 `arguments`로부터 독립된 키를 만들어냅니다. 여기에 간단한 "joining" 함수를 만들어서 `(3, 5)`를 `"3,5"`키값으로 반환하게 합니다. 더 복잡한 경우에는 다른 해시 함수가 필요하겠지만요. +- 그다음엔 `(**)`이 `func.apply`를 사용해서 래퍼가 가진 컨텍스트와 모든 인수를 (몇 개든 상관없이) 원래의 함수로 전달합니다. -Instead of `func.call(this, ...arguments)` we could use `func.apply(this, arguments)`. +`func.call(this, ...arguments)` 대신에 `func.apply(this, arguments)`를 사용할 수 있습니다. -The syntax of built-in method [func.apply](mdn:js/Function/apply) is: +내장 함수 [func.apply](mdn:js/Function/apply)의 문법은 다음과 같습니다. ```js func.apply(context, args) ``` -It runs the `func` setting `this=context` and using an array-like object `args` as the list of arguments. +func.apply는 `this=context`로 설정된 `func`를 실행하고 유사 배열 객체인 `args`를 인수로 사용합니다. -The only syntax difference between `call` and `apply` is that `call` expects a list of arguments, while `apply` takes an array-like object with them. +오직 `call`과 `apply`의 문법상의 차이는 `call`은 인수를 리스트 형태로 받고 `apply`는 유사 배열 객체로 받는 것입니다. -So these two calls are almost equivalent: +그래서 아래 두 가지 호출은 거의 유사합니다. ```js -func.call(context, ...args); // pass an array as list with spread operator -func.apply(context, args); // is same as using apply +func.call(context, ...args); // 전개 연산자를 사용해서 배열을 리스트로 전달 +func.apply(context, args); // apply를 사용하는 것과 같음 ``` -There's only a minor difference: +여기에는 아주 사소한 차이가 있습니다. -- The spread operator `...` allows to pass *iterable* `args` as the list to `call`. -- The `apply` accepts only *array-like* `args`. +- 전개 연산자 `...`는 *반복 가능한* `args`를 리스트로 `call`에 전달할 수 있게 합니다. +- `apply`는 오직 *유사 배열* `args`만 허용합니다. -So, these calls complement each other. Where we expect an iterable, `call` works, where we expect an array-like, `apply` works. +그래서 두 가지 호출은 서로를 보완합니다. 반복 가능할 때는 `call`을 사용하고 유사 배열일 경우에는 `apply`를 사용하는 것이죠. -And for objects that are both iterable and array-like, like a real array, we technically could use any of them, but `apply` will probably be faster, because most JavaScript engines internally optimize it better. +그리고 객체가 반복 가능하면서 유사 배열(실제 배열)이면 기술적으로 아무것이나 사용해도 되지만 `apply`가 아마도 빠르게 동작할 것입니다. 왜냐하면 대부분의 자바스크립트 엔진은 내부적으로 최적화가 잘 되어있기 때문이죠. -Passing all arguments along with the context to another function is called *call forwarding*. +모든 인수를 해당하는 컨텍스트와 모두 다른 함수에 전달하는 것을 *call forwarding*이라고 합니다. -That's the simplest form of it: +다음은 가장 간단한 call forwarding 형식입니다. ```js let wrapper = function() { @@ -322,11 +325,11 @@ let wrapper = function() { }; ``` -When an external code calls such `wrapper`, it is indistinguishable from the call of the original function `func`. +외부 코드가 `wrapper`를 호출할 때 원래 함수 `func`의 호출과 구별할 수 없습니다. -## Borrowing a method [#method-borrowing] +## 메서드 빌리기 [#method-borrowing] -Now let's make one more minor improvement in the hashing function: +이제 해시 함수를 조금 개선해보겠습니다. ```js function hash(args) { @@ -334,9 +337,9 @@ function hash(args) { } ``` -As of now, it works only on two arguments. It would be better if it could glue any number of `args`. +위의 예시는 아직까진 두 개의 인수로만 작동합니다만, 몇 개의 `args`이던지 상관없이 작동하게 된다면 더 좋을 것 같습니다. -The natural solution would be to use [arr.join](mdn:js/Array/join) method: +그렇게 하기 위해서는 [arr.join](mdn:js/Array/join) 메서드를 사용할 수 있습니다. ```js function hash(args) { @@ -344,21 +347,21 @@ function hash(args) { } ``` -...Unfortunately, that won't work. Because we are calling `hash(arguments)` and `arguments` object is both iterable and array-like, but not a real array. +그런데…. 안타깝게도, 위의 예시는 작동하지 않습니다. 왜냐하면 `hash(arguments)`와 `arguments` 객체 모두 정규 배열은 아니면서 iterable 이고 유사 배열이기 때문이죠, -So calling `join` on it would fail, as we can see below: +그래서 아래 예시처럼 `join`을 호출하는 것은 실패할 것입니다. ```js run function hash() { *!* - alert( arguments.join() ); // Error: arguments.join is not a function + alert( arguments.join() ); // 에러, arguments.join은 함수가 아님 */!* } hash(1, 2); ``` -Still, there's an easy way to use array join: +여전히, 배열을 쉽게 join하는 방법은 있습니다. ```js run function hash() { @@ -370,48 +373,40 @@ function hash() { hash(1, 2); ``` -The trick is called *method borrowing*. - -We take (borrow) a join method from a regular array `[].join`. And use `[].join.call` to run it in the context of `arguments`. - -Why does it work? - -That's because the internal algorithm of the native method `arr.join(glue)` is very simple. - -Taken from the specification almost "as-is": +위와 같은 방법을 *메서드 빌리기(method borrowing)* 라고 합니다. -1. Let `glue` be the first argument or, if no arguments, then a comma `","`. -2. Let `result` be an empty string. -3. Append `this[0]` to `result`. -4. Append `glue` and `this[1]`. -5. Append `glue` and `this[2]`. -6. ...Do so until `this.length` items are glued. -7. Return `result`. +정규 배열 `[].join`에서 join 메서드를 가져오고 `[] .join.call`을 사용하여 `arguments`의 컨텍스트 안에서 동작하게 됩니다. -So, technically it takes `this` and joins `this[0]`, `this[1]` ...etc together. It's intentionally written in a way that allows any array-like `this` (not a coincidence, many methods follow this practice). That's why it also works with `this=arguments`. +어떻게 이런 방법이 작동할까요? -## Decorators and function properties +그 이유는 네이티브 메서드인 `arr.join(glue)`의 내부 알고리즘이 매우 간결하기 때문입니다. -It is generally safe to replace a function or a method with a decorated one, except for one little thing. If the original function had properties on it, like `func.calledCount` or whatever, then the decorated one will not provide them. Because that is a wrapper. So one needs to be careful if one uses them. +거의 명세서를 "있는 그대로" 따르고 있습니다. -E.g. in the example above if `slow` function had any properties on it, then `cachingDecorator(slow)` is a wrapper without them. +1.`glue`를 첫 번째 인수로, 인수가 없으면 쉼표`","`합니다. +2. `result`를 빈 문자열로 둡니다. +3. `this[0]`을`result`에 추가합니다. +4. `glue`와 `this[1]`을 추가합니다. +5. `glue`와 `this[2]`를 추가합니다. +6. `this.length` 길이의 아이템만큼 계속됩니다. +7. `result`를 반환합니다. -Some decorators may provide their own properties. E.g. a decorator may count how many times a function was invoked and how much time it took, and expose this information via wrapper properties. +위와 같은 기술적인 이유로 `this`를 가져가서 `this[0]`, `this[1]` 등을 join 합니다. 이 방법은 의도적으로 모든 배열을 허용하는 방식으로 작성되었습니다.(우연이 아니라, 이렇게 하는 데는 많은 메서드가 필요합니다.) 그래서 `this = arguments`와 함께 작동합니다. -There exists a way to create decorators that keep access to function properties, but this requires using a special `Proxy` object to wrap a function. We'll discuss it later in the article . +## 요약 -## Summary +*데코레이터*는 함수의 행동을 변환하는 래퍼입니다. 실제 작업은 전달되는 함수에 의해 진행됩니다. -*Decorator* is a wrapper around a function that alters its behavior. The main job is still carried out by the function. +일반적으로 하나의 함수나 하나의 메서드를 하나로 데코레이트 하는 것이 안전합니다. 원래 함수가 `func.calledCount` 또는 어떠한 속성을 가지고 있다면, 그것은 래퍼이기 때문에 데코레이트 된 후의 함수는 프로퍼티를 가지고 있지 않습니다. 데코레이터는 자신만의 프로퍼티를 제공하기 때문에 데코레이터를 사용할 때는 신중해야 합니다. -Decorators can be seen as "features" or "aspects" that can be added to a function. We can add one or add many. And all this without changing its code! +데코레이터는 한 개 또는 여러 개의 "기능(feature)" 또는 "관점(aspect)"을 원래 함수를 변경하지 않고 주입할 수 있습니다. -To implement `cachingDecorator`, we studied methods: +`cachingDecorator`를 구현하기 위해서 다음과 같은 메서드를 살펴보았습니다. -- [func.call(context, arg1, arg2...)](mdn:js/Function/call) -- calls `func` with given context and arguments. -- [func.apply(context, args)](mdn:js/Function/apply) -- calls `func` passing `context` as `this` and array-like `args` into a list of arguments. +- [func.call(context, arg1, arg2...)](mdn:js/Function/call) -- `func`를 주어진 컨텍스트와 인수들과 호출합니다. +- [func.apply(context, args)](mdn:js/Function/apply) -- `func`를 `context`가 `this`로 넘겨진 것과 유사 배열 `args`가 인수들의 리스트로 받아서 호출합니다. -The generic *call forwarding* is usually done with `apply`: +일반적인 *call forwarding*은 보통 `apply`를 통해 이루어집니다. ```js let wrapper = function() { @@ -419,6 +414,6 @@ let wrapper = function() { }; ``` -We also saw an example of *method borrowing* when we take a method from an object and `call` it in the context of another object. It is quite common to take array methods and apply them to `arguments`. The alternative is to use rest parameters object that is a real array. +*메서드 빌리기*의 방법 또한 알아보았습니다. 해당 객체의 메서드를 다른 객체의 컨텍스트 안에서 `호출`되었습니다. 배열 메서드를 가지고 와서 `인수`로 전달하는 것은 자주 쓰이는 방법입니다. 다른 방법으로는 정규 배열인 나머지 매개변수 객체를 사용하는 것입니다. -There are many decorators there in the wild. Check how well you got them by solving the tasks of this chapter. +데코레이터는 실제로 더 많이 있습니다. 이번 챕터에서 문제를 어떤 방식으로 해결했는지 다시 한번 확인해 보세요. From d910a6079bc16e24cf18d3fe3e03c8b41745359c Mon Sep 17 00:00:00 2001 From: Chris-D-Lee Date: Fri, 25 Oct 2019 12:01:07 +1100 Subject: [PATCH 2/2] =?UTF-8?q?[=EB=8D=B0=EC=BD=94=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=ED=84=B0]=20=EB=A6=AC=EB=B7=B0=EB=B0=98=EC=98=81=20=EB=B0=8F?= =?UTF-8?q?=20=EB=88=84=EB=9D=BD=EB=B6=80=EB=B6=84=EB=B2=88=EC=97=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../03-debounce/task.md | 10 +++--- .../09-call-apply-decorators/article.md | 31 +++++++++++-------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md index 74a4ff31d8..0c0303a781 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md @@ -4,21 +4,21 @@ importance: 5 # 디바운스 데코레이터 -`debounce(f, ms)`데코레이터는 `ms`밀리초 마다 최대값에 한번 `f` 에 호출을 전달하는 래퍼이어야 합니다. +`debounce(f, ms)`데코레이터는 `ms` 밀리초 마다 최댓값에 한번 `f` 에 호출을 전달하는 래퍼이어야 합니다. -다르게 표현하면 "debounced" 함수를 호출하면 `ms` 밀리초 미만의 함수에 대한 다른 함수 호출은 이전 함수 호출 후 무시되어야 합니다. +다르게 표현하면 "debounced" 함수를 호출하면 `ms` 밀리초 미만의 함수에 대한 다른 함수호출은 이전 함수 호출 후 무시돼야 합니다. 예를 들면 ```js no-beautify let f = debounce(alert, 1000); -f(1); // 바로 실행됩니다. +f(1); // 바로 실행됩니다 f(2); // 무시됩니다. -setTimeout( () => f(3), 100); // 무시됨 ( 오직 100 만 전달됨 ) +setTimeout( () => f(3), 100); // 무시됨 ( 100ms밖에 지나지 않았음 ) setTimeout( () => f(4), 1100); // 실행됨 setTimeout( () => f(5), 1500); // 무시됨 (마지막 실행 후에 1000ms 가 지나지 않았음) ``` -In practice `debounce` is useful for functions that retrieve/update something when we know that nothing new can be done in such a short period of time, so it's better not to waste resources. +실제로 `debounce`는 검색/업데이트하는 함수가 짧은 시간 내에 새로운 작업을 진행될 수 없다는 것을 알고 있을 때 유용하므로 자원을 낭비하지 않는 것이 좋습니다. diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/article.md b/1-js/06-advanced-functions/09-call-apply-decorators/article.md index 6b988ad9b2..52bc0ee72c 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/article.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/article.md @@ -61,7 +61,6 @@ alert( "Again: " + slow(2) ); // 이전 라인과 같습니다. - 캐싱하는 로직이 분리됩니다. `slow` 함수 (다른 함수들이 되더라도) 자체를 복잡하게 만들지 않습니다. - 필요에 따라 여러 개의 데코레이터를 섞어서 사용할 수 있습니다.(다른 데코레이터에 대해서는 곧 알아보겠습니다.) - ## "func.call"을 컨텍스트에 사용하기 위에서 언급한 캐싱 데코레이터는 객체 메서드와 사용하기엔 적합하지 않습니다. @@ -102,7 +101,7 @@ alert( worker.slow(1) ); // 원래 메서드는 작동함 worker.slow = cachingDecorator(worker.slow); // 캐싱을 생성 *!* -alert( worker.slow(2) ); // 에러, 정의되지 않은 'someMethod'프로퍼티를 읽을 수 없음 +alert( worker.slow(2) ); // Error: Cannot read property 'someMethod' of undefined */!* ``` @@ -168,10 +167,8 @@ let user = { name: "John" }; say.call( user, "Hello" ); // John: Hello ``` - 아래 예시에서는, `call`을 래퍼 안에서 사용해서 원래의 함수에 컨텍스트를 전달합니다. - ```js run let worker = { someMethod() { @@ -354,7 +351,7 @@ function hash(args) { ```js run function hash() { *!* - alert( arguments.join() ); // 에러, arguments.join은 함수가 아님 + alert( arguments.join() ); // Error: arguments.join is not a function */!* } @@ -383,22 +380,30 @@ hash(1, 2); 거의 명세서를 "있는 그대로" 따르고 있습니다. -1.`glue`를 첫 번째 인수로, 인수가 없으면 쉼표`","`합니다. -2. `result`를 빈 문자열로 둡니다. -3. `this[0]`을`result`에 추가합니다. -4. `glue`와 `this[1]`을 추가합니다. -5. `glue`와 `this[2]`를 추가합니다. +1. `glue`를 첫 번째 인수로 하거나 만약에 인수가 없으면 쉼표`","`를 인수로 합니다. +2. `result` 를 빈 문자열로 둡니다. +3. `this [0]`을`result` 에 추가합니다. +4. `glue` 와 `this [1]` 을 추가합니다. +5. `glue` 와 `this [2]` 를 추가합니다. 6. `this.length` 길이의 아이템만큼 계속됩니다. 7. `result`를 반환합니다. -위와 같은 기술적인 이유로 `this`를 가져가서 `this[0]`, `this[1]` 등을 join 합니다. 이 방법은 의도적으로 모든 배열을 허용하는 방식으로 작성되었습니다.(우연이 아니라, 이렇게 하는 데는 많은 메서드가 필요합니다.) 그래서 `this = arguments`와 함께 작동합니다. +위와 같은 기술적인 이유로 `this`를 가져가서 `this[0]`, `this[1]` ...기타등등을 join 합니다. 이 방법은 의도적으로 모든 배열을 허용하는 방식으로 작성되었습니다. (우연이 아니라, 이렇게 하는 데는 많은 메서드들이 필요합니다). 그래서 `this = arguments`와 함께 작동합니다. + +## 데코레이터와 함수 프로퍼티 + +아주 작은 하나일 경우일 때를 제외하면 보통 하나의 함수를 대체하거나 하나의 메서드를 하나에 하나의 데코레이터를 사용하는 것이 안전합니다. 만약에 원래의 함수가 `func.calledCount` 이든 뭐든 프로퍼티를 가지고 있다면 데코레이터는 해당 프로퍼티를 제공하지 않습니다. 왜냐하면 데코레이터는 하나의 래퍼일 뿐이니까요. 그래서 함수가 프로퍼티를 사용하고 있다면 데코레이터를 적용할 때 주의를 해야 합니다. + +위의 예시에서 보면 함수 `slow`가 프로퍼티가 있었다면 `cachingDecorator(slow)`는 그것의 프로퍼티를 가지고 있지 않은 래퍼일 뿐이죠. + +몇 가지 데코레이터는 자체 프로퍼티를 제공할 수도 있습니다. 예를 들어 데코레이터가 함수 호출 시 소요된 시간과 횟수를 계산한 정보를 래퍼의 프로퍼티를 사용해서 결과를 내보낼 수 있습니다. + +데코레이터를 생성할 때 함수의 프로퍼티에 대한 접근을 가능하게 해주는 방법은 존재합니다만 함수에 래퍼를 적용하기 위해 특별한 `Proxy` 객체를 사용해야 합니다. Proxy에 대해서는 나중에 장에서 설명하겠습니다. ## 요약 *데코레이터*는 함수의 행동을 변환하는 래퍼입니다. 실제 작업은 전달되는 함수에 의해 진행됩니다. -일반적으로 하나의 함수나 하나의 메서드를 하나로 데코레이트 하는 것이 안전합니다. 원래 함수가 `func.calledCount` 또는 어떠한 속성을 가지고 있다면, 그것은 래퍼이기 때문에 데코레이트 된 후의 함수는 프로퍼티를 가지고 있지 않습니다. 데코레이터는 자신만의 프로퍼티를 제공하기 때문에 데코레이터를 사용할 때는 신중해야 합니다. - 데코레이터는 한 개 또는 여러 개의 "기능(feature)" 또는 "관점(aspect)"을 원래 함수를 변경하지 않고 주입할 수 있습니다. `cachingDecorator`를 구현하기 위해서 다음과 같은 메서드를 살펴보았습니다.