Skip to content

[재작업] 1-js/09-classes/02-class-inheritance 백틱수정및 재검토 #323

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions 1-js/06-advanced-functions/01-recursion/01-sum-to/solution.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
반복문 사용하기:
반복문 사용하기
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기는 :를 왜 빼셨나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

끄아아아아~~ squash rebase 하다 잘못 합쳐진듯 합니다!! ㅠㅠ


```js run
function sumTo(n) {
Expand All @@ -12,7 +12,7 @@ function sumTo(n) {
alert( sumTo(100) );
```

재귀 사용하기:
재귀 사용하기
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기는 :를 왜 빼셨나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

살려주세요!!!


```js run
function sumTo(n) {
Expand All @@ -23,7 +23,7 @@ function sumTo(n) {
alert( sumTo(100) );
```

등차수열의 합공식 `sumTo(n) = n*(n+1)/2` 사용하기:
등차수열의 합공식 `sumTo(n) = n*(n+1)/2` 사용하기
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기는 :를 왜 빼셨나요?


```js run
function sumTo(n) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ importance: 4
n! = n * (n - 1) * (n - 2) * ...*1
```

자연수 `n`에 대한 `n` 팩토리얼:
자연수 `n`에 대한 `n` 팩토리얼
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기는 :를 왜 빼셨나요?


```js
1! = 1
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
The first solution we could try here is the recursive one.
첫번째 해결방법은 재귀를 이용한 것입니다.

Fibonacci numbers are recursive by definition:
피보나치 수들은 정의에 따라 재귀적입니다.
Comment on lines 1 to +5
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

원문이 남아있습니다.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

끄아아아.. 다른 브랜치인데 같이 합쳐졌어요 ㅠㅠ 수정하겠습니다


```js run
function fib(n) {
Expand All @@ -9,14 +11,17 @@ function fib(n) {

alert( fib(3) ); // 2
alert( fib(7) ); // 13
// fib(77); // will be extremely slow!
// fib(77); // 엄청나게 느릴것입니다!
```

...But for big values of `n` it's very slow. For instance, `fib(77)` may hang up the engine for some time eating all CPU resources.
...하지만 `n`의 값이 클경우 매우 느립니다. 예를 들어,`fib (77)`은 한동안 모든 CPU 리소스를 먹어서 자바스크립트 엔진을 정지시킬 수 있습니다.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

맨 앞 ...을 빼주세요


That's because the function makes too many subcalls. The same values are re-evaluated again and again.
함수가 너무 많은 하위 호출을 하기 때문입니다. 동일한 값들이 반복해서 재평가 됩니다.

For instance, let's see a piece of calculations for `fib(5)`:
아래 예시를 통해 `fib(5)`의 계산을 살펴보겠습니다.

```js no-beautify
...
Expand All @@ -26,22 +31,30 @@ fib(4) = fib(3) + fib(2)
```

Here we can see that the value of `fib(3)` is needed for both `fib(5)` and `fib(4)`. So `fib(3)` will be called and evaluated two times completely independently.
예시에서 처럼 `fib (3)` 의 값이 `fib (5)` 와 `fib (4)` 모두에 필요하다는 것을 알 수 있습니다. 따라서 `fib(3)`은 두번이나 완전히 독립적으로 호출되고 평가됩니다.

Here's the full recursion tree:
전체 재귀 트리는 다음과 같습니다.

![fibonacci recursion tree](fibonacci-recursion-tree.svg)

We can clearly notice that `fib(3)` is evaluated two times and `fib(2)` is evaluated three times. The total amount of computations grows much faster than `n`, making it enormous even for `n=77`.
`fib (3)`는 두 번 평가되고`fib (2)`는 세 번 평가된다는 것을 분명히 알 수 있습니다. 총 계산량은 `n` 보다 훨씬 빠르게 증가하여 `n = 77` 에서도 엄청납니다.

We can optimize that by remembering already-evaluated values: if a value of say `fib(3)` is calculated once, then we can just reuse it in future computations.
이미 평가 된 값을 기억함으로써이를 최적화 할 수 있습니다. 만약`fib (3)`의 값이 한 번 계산된다면, 그것은 나중에 계산에서 재사용 할 수 있습니다.

Another variant would be to give up recursion and use a totally different loop-based algorithm.
또 다른 변형은 재귀를 포기하고 완전히 다른 루프 기반 알고리즘을 사용하는 것입니다.

Instead of going from `n` down to lower values, we can make a loop that starts from `1` and `2`, then gets `fib(3)` as their sum, then `fib(4)` as the sum of two previous values, then `fib(5)` and goes up and up, till it gets to the needed value. On each step we only need to remember two previous values.
`n`에서 더 낮은 값으로 이동하는 대신`1`과`2`에서 시작하여`fib (3)`을 합계로 가져온 다음`fib (4)`를 합계로 얻는 루프를 만들 수 있습니다 두 개의 이전 값 중 'fib (5)'를 입력 한 다음 필요한 값에 도달 할 때까지 위로 이동합니다. 각 단계에서 두 개의 이전 값만 기억하면됩니다.

Here are the steps of the new algorithm in details.
새로운 알고리즘의 단계는 다음과 같습니다.

The start:
시작은 이렇습니다

```js
// a = fib(1), b = fib(2), these values are by definition 1
Expand All @@ -57,8 +70,10 @@ a b c
```

Now we want to get `fib(4) = fib(2) + fib(3)`.
이제 `fib(4) = fib(2) + fib(3)`값을 얻고 싶습니다.

Let's shift the variables: `a,b` will get `fib(2),fib(3)`, and `c` will get their sum:
변수를 바꿔 봅시다 :`a, b`는`fib (2), fib (3)`을,`c`는 합을 얻습니다 :

```js no-beautify
a = b; // now a = fib(2)
Expand All @@ -72,6 +87,7 @@ c = a + b; // c = fib(4)
```

The next step gives another sequence number:
다음 단계는 다른 시퀀스 번호를 제공합니다.

```js no-beautify
a = b; // now a = fib(3)
Expand All @@ -85,8 +101,11 @@ c = a + b; // c = fib(5)
```

...And so on until we get the needed value. That's much faster than recursion and involves no duplicate computations.
... 필요한 가치를 얻을 때까지 계속됩니다. 재귀보다 훨씬 빠르며 중복 계산이 필요하지 않습니다.

The full code:
전체 코드 :


```js run
function fib(n) {
Expand All @@ -106,5 +125,7 @@ alert( fib(77) ); // 5527939700884757
```

The loop starts with `i=3`, because the first and the second sequence values are hard-coded into variables `a=1`, `b=1`.
루프는 'i = 3'으로 시작하는데, 첫 번째와 두 번째 시퀀스 값은 변수 'a = 1',`b = 1`로 하드 코딩되기 때문입니다.

The approach is called [dynamic programming bottom-up](https://en.wikipedia.org/wiki/Dynamic_programming).
이러한 방법을 [dynamic programming bottom-up](https://en.wikipedia.org/wiki/Dynamic_programming).
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Loop-based solution
# 루프를 이용한 방법

The loop-based variant of the solution:
루프를 기반에 두고 변형한 해결방법은 다음과 같습니다.

```js run
let list = {
Expand Down Expand Up @@ -31,6 +31,7 @@ printList(list);
```

Please note that we use a temporary variable `tmp` to walk over the list. Technically, we could use a function parameter `list` instead:
목록을 살펴보기 위해 임시 변수 `tmp`를 사용한다는 점에 유의하십시오. 기술적으로 함수 매개 변수 `list` 를 대신 사용할 수 있습니다.

```js
function printList(list) {
Expand All @@ -49,9 +50,18 @@ Talking about good variable names, `list` here is the list itself. The first ele

From the other side, the role of `tmp` is exclusively a list traversal, like `i` in the `for` loop.


그러나 그것은 현명하지 않을 것입니다. 앞으로 함수를 확장하고 목록으로 다른 작업을 수행해야 할 수도 있습니다. `list` 을 바꾸면 그러한 능력을 잃게됩니다.

좋은 변수 이름에 대해 이야기하면 여기에 `list` 가 있습니다. 그것의 첫 번째 요소. 그리고 그렇게 남아 있어야합니다. 명확하고 신뢰할 수 있습니다.

다른면에서 `tmp` 의 역할은 전적으로 `for` 루프의 `i` 와 같은 목록 순회입니다.

# Recursive solution
# 재귀적인 해결방법

The recursive variant of `printList(list)` follows a simple logic: to output a list we should output the current element `list`, then do the same for `list.next`:
`printList (list)`의 재귀 변형은 간단한 논리를 따릅니다.리스트를 출력하려면 현재 요소 `list` 를 출력 한 다음` list.next` 에 대해서도 동일하게 수행해야합니다.

```js run
let list = {
Expand All @@ -70,10 +80,10 @@ let list = {

function printList(list) {

alert(list.value); // output the current item
alert(list.value); // 현재 아이템을 출력합니다

if (list.next) {
printList(list.next); // do the same for the rest of the list
printList(list.next); // list 안의 나머지 값들에 대해 똑같은 처리를 합니다
}

}
Expand All @@ -86,3 +96,9 @@ Now what's better?
Technically, the loop is more effective. These two variants do the same, but the loop does not spend resources for nested function calls.

From the other side, the recursive variant is shorter and sometimes easier to understand.

이제 더 좋은게 뭐야?

기술적으로 루프가 더 효과적입니다. 이 두 변형은 동일하지만 루프는 중첩 된 함수 호출에 자원을 소비하지 않습니다.

반면에 재귀 변형은 더 짧고 때로는 이해하기 쉽습니다.
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
# Using a recursion
# 재귀 사용하기

The recursive logic is a little bit tricky here.

We need to first output the rest of the list and *then* output the current one:
재귀 논리는 여기에서 약간 까다 롭습니다.

먼저 나머지리스트를 출력 한 *다음* 현재리스트를 출력해야합니다 :

```js run
let list = {
Expand Down Expand Up @@ -32,13 +36,21 @@ printReverseList(list);
```

# Using a loop
# 루프 사용하기

The loop variant is also a little bit more complicated then the direct output.

There is no way to get the last value in our `list`. We also can't "go back".

So what we can do is to first go through the items in the direct order and remember them in an array, and then output what we remembered in the reverse order:


루프 변형은 직접 출력보다 약간 더 복잡합니다.

`list`에서 마지막 값을 얻는 방법은 없습니다. 우리는 또한 "돌아갈"수 없습니다.

따라서 우리가 할 수있는 일은 먼저 직접 순서대로 항목을 살펴보고 배열로 기억 한 다음 기억 한 것을 역순으로 출력하는 것입니다.

```js run
let list = {
value: 1,
Expand Down Expand Up @@ -72,3 +84,4 @@ printReverseList(list);
```

Please note that the recursive solution actually does exactly the same: it follows the list, remembers the items in the chain of nested calls (in the execution context stack), and then outputs them.
재귀 솔루션은 실제로 정확히 동일합니다. 이는 목록을 따르고 (실행 컨텍스트 스택에서) 중첩 호출 체인의 항목을 기억 한 다음 출력합니다.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
That's because the child constructor must call `super()`.
인스턴스를 생성할 수 없었던 이유는 자식의 생성자가 `super()`를 호출해야 하기 때문입니다.

Here's the corrected code:
아래에 올바른 코드가 있습니다.

```js run
class Animal {
Expand All @@ -21,7 +21,7 @@ class Rabbit extends Animal {
}

*!*
let rabbit = new Rabbit("White Rabbit"); // ok now
let rabbit = new Rabbit("White Rabbit"); // 이제 생성됩니다
*/!*
alert(rabbit.name); // White Rabbit
```
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ importance: 5

---

# Error creating an instance
# 인스턴스 생성 오류

Here's the code with `Rabbit` extending `Animal`.
아래에 `Animal` 클래스를 상속하는 `Rabbit` 코드가 있습니다.

Unfortunately, `Rabbit` objects can't be created. What's wrong? Fix it.
아직은 `Rabbit` 객체를 생성할 수 없습니다. 무엇이 잘못된 것일까요? 코드를 수정해보세요.
```js run
class Animal {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ importance: 5

---

# Extended clock
# 시계 확장하기

We've got a `Clock` class. As of now, it prints the time every second.

`Clock`이라는 매초 시간을 출력하는 클래스가 있습니다.

[js src="source.view/clock.js"]

Create a new class `ExtendedClock` that inherits from `Clock` and adds the parameter `precision` -- the number of `ms` between "ticks". Should be `1000` (1 second) by default.
`Clock`을 상속하는 `ExtendedClock`을 생성해서 `precision`이라는 "ticks" 사이에 `ms` 단위로 된 매개변수를 추가해보세요. 1000 (1초)를 기본값으로 하는 것이 좋습니다.

- Your code should be in the file `extended-clock.js`
- Don't modify the original `clock.js`. Extend it.
- 코드는 `extended-clock.js`라는 독립적인 파일에 작성하는 것이 좋습니다.
- 오리지널 `clock.js`를 수정하지 마세요. 확장하세요.
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
First, let's see why the latter code doesn't work.
먼저, 해당 코드가 왜 작동하지 않는지 살펴봐야 합니다.

The reason becomes obvious if we try to run it. An inheriting class constructor must call `super()`. Otherwise `"this"` won't be "defined".
이유는 코드를 실행한다면 명백해 보입니다. 상속받는 클래스는 `super()`를 반드시 호출해야 합니다. 그렇지 않으면 `"this"` 는 "정의"되지 않기 때문이죠.

So here's the fix:
아래 수정된 코드가 있습니다.

```js run
class Rabbit extends Object {
constructor(name) {
*!*
super(); // need to call the parent constructor when inheriting
super(); // 상속할 때 부모의 생성자를 호출해야 합니다.
*/!*
this.name = name;
}
Expand All @@ -19,16 +19,16 @@ let rabbit = new Rabbit("Rab");
alert( rabbit.hasOwnProperty('name') ); // true
```

But that's not all yet.
그런데 그게 전부는 아닙니다.

Even after the fix, there's still important difference in `"class Rabbit extends Object"` versus `class Rabbit`.
위와 같이 수정한다고 해도, 여전히 `"class Rabbit extends Object"``class Rabbit` 사이에는 다른 점이 존재합니다.

As we know, the "extends" syntax sets up two prototypes:
이미 배웠듯이, "extends" 문법은 두 개의 프로토타입을 설정합니다.

1. Between `"prototype"` of the constructor functions (for methods).
2. Between the constructor functions themselves (for static methods).
1. 생성자 함수들의 `"prototype"` 사이에 (메서드를 위한 것)
2. 생성자 함수 자신들 사이에 (정적인 메서드를 위한 것)

In our case, for `class Rabbit extends Object` it means:
예제의 경우에는, `class Rabbit extends Object`가 뜻하는 것은 아래와 같습니다.

```js run
class Rabbit extends Object {}
Expand All @@ -37,45 +37,45 @@ alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) true
```

So `Rabbit` now provides access to static methods of `Object` via `Rabbit`, like this:
그래서 `Rabbit` `Object` 의 정적인 메서드에 `Rabbit` 을 통해서 접근할 수 있게 해야 합니다. 아래와 같이 말이죠.

```js run
class Rabbit extends Object {}

*!*
// normally we call Object.getOwnPropertyNames
// 보통은 Object.getOwnPropertyNames 로 호출합니다
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // a,b
*/!*
```

But if we don't have `extends Object`, then `Rabbit.__proto__` is not set to `Object`.
그러나 `extends Object`가 없다면, `Rabbit.__proto__` `Object`로 설정되지 않습니다.

Here's the demo:
아래에 예시가 있습니다.

```js run
class Rabbit {}

alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) false (!)
alert( Rabbit.__proto__ === Function.prototype ); // as any function by default
alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) (true Rabbit의 프로토타입은 객체의 프로토타입입니다. - Chris)
alert( Rabbit.__proto__ === Object ); // (2) false (!) (Rabbit의 프로토타입은 객체가 아닙니다. - Chris)
alert( Rabbit.__proto__ === Function.prototype ); // 어떠한 함수든 기본으로 (__proto__는 함수의 프로토타입입니다. - Chris)

*!*
// error, no such function in Rabbit
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // 에러
*/!*
```

So `Rabbit` doesn't provide access to static methods of `Object` in that case.
그래서 `Rabbit``Object`의 정적 메서드에 접근을 할 수 없습니다.

By the way, `Function.prototype` has "generic" function methods, like `call`, `bind` etc. They are ultimately available in both cases, because for the built-in `Object` constructor, `Object.__proto__ === Function.prototype`.
어쨌든 `Function.prototype` `call`, `bind` 기타 등등의 "제네릭" 함수의 메서드를 가집니다. 제네릭 함수들은 궁극적으로 두 가지 경우에 모두 사용 가능합니다. 왜냐하면, `Object`의 내장된 생성자는 `Object.__proto__ === Function.prototype` 이기 때문이죠.

Here's the picture:
이해를 돕기 위한 그림이 있습니다.

![](rabbit-extends-object.svg)

So, to put it short, there are two differences:
그래서, 짧게 요약하면 두 가지 다른 점이 있습니다.

| class Rabbit | class Rabbit extends Object |
|--------------|------------------------------|
| -- | needs to call `super()` in constructor |
| -- | `super()`를 생성자에서 호출해야 합니다. |
| `Rabbit.__proto__ === Function.prototype` | `Rabbit.__proto__ === Object` |
Loading