diff --git a/1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md index 4711e48271..657da3ecf3 100644 --- a/1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md +++ b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md @@ -1,6 +1,6 @@ -That's because the child constructor must call `super()`. +인스턴스를 생성할 수 없었던 이유는 자식의 생성자가 `super()`를 호출해야 하기 때문입니다. -Here's the corrected code: +아래에 올바른 코드가 있습니다. ```js run class Animal { @@ -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 ``` diff --git a/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md index 380a4720b2..18fd76ac8c 100644 --- a/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md +++ b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md @@ -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 { diff --git a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md index bbc2c6a43c..c16863af69 100644 --- a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md +++ b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md @@ -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`이라는 매개변수를 추가해보세요. `precision`은 '초' 사이의 간격을 의미하고, 기본값은 `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`를 수정하지 마세요. 확장하세요. diff --git a/1-js/09-classes/02-class-inheritance/3-class-extend-object/solution.md b/1-js/09-classes/02-class-inheritance/3-class-extend-object/solution.md index ca9e80601b..fc9d7f1fea 100644 --- a/1-js/09-classes/02-class-inheritance/3-class-extend-object/solution.md +++ b/1-js/09-classes/02-class-inheritance/3-class-extend-object/solution.md @@ -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; } @@ -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 {} @@ -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` | diff --git a/1-js/09-classes/02-class-inheritance/3-class-extend-object/task.md b/1-js/09-classes/02-class-inheritance/3-class-extend-object/task.md index b82a4255e9..1e692c8787 100644 --- a/1-js/09-classes/02-class-inheritance/3-class-extend-object/task.md +++ b/1-js/09-classes/02-class-inheritance/3-class-extend-object/task.md @@ -2,11 +2,11 @@ importance: 5 --- -# Class extends Object? +# 객체를 확장하는 클래스? -As we know, all objects normally inherit from `Object.prototype` and get access to "generic" object methods like `hasOwnProperty` etc. +이미 살펴보았듯이, 보통 모든 객체들은 `Object.prototype` 으로 부터 상속되고 `hasOwnProperty` 같은 "generic(제네릭)" 객체의 메서드에 접근이 가능합니다. -For instance: +아래 예시가 있습니다. ```js run class Rabbit { @@ -18,16 +18,16 @@ class Rabbit { let rabbit = new Rabbit("Rab"); *!* -// hasOwnProperty method is from Object.prototype +// hasOwnProperty 메서드는 Object.prototype 으로 부터 왔습니다. alert( rabbit.hasOwnProperty('name') ); // true */!* ``` -But if we spell it out explicitly like `"class Rabbit extends Object"`, then the result would be different from a simple `"class Rabbit"`? +그런데 만약에 명시적으로 `"class Rabbit extends Object"` 라고 사용한다면, 결과는 간단히 `"class Rabbit"`로 사용하는 것과 다를까요? -What's the difference? +그렇다면 무엇이 다를까요? -Here's an example of such code (it doesn't work -- why? fix it?): +아래에 작동하지 않는 예시가 있습니다. 어디가 잘못된 것일까요? 작동하게 수정할 수 있을까요? ```js class Rabbit extends Object { diff --git a/1-js/09-classes/02-class-inheritance/article.md b/1-js/09-classes/02-class-inheritance/article.md index d1685f20a8..a2cff44331 100644 --- a/1-js/09-classes/02-class-inheritance/article.md +++ b/1-js/09-classes/02-class-inheritance/article.md @@ -1,13 +1,13 @@ -# Class inheritance +# 클래스 상속 -Class inheritance is a way for one class to extend another class. +클래스 상속은 하나의 클래스를 다른 클래스로 확장하는 방법입니다. -So we can create new functionality on top of the existing. +그래서 존재하는 클래스 위에 새로운 기능을 추가할 수 있죠. -## The "extends" keyword +## "extends" 키워드 -Let's say with have class `Animal`: +아래와 같이 `Animal`이라는 클래스가 있다고 가정해보죠. ```js class Animal { @@ -28,17 +28,17 @@ class Animal { let animal = new Animal("My animal"); ``` -Here's how we can represent `animal` object and `Animal` class graphically: +아래에 `animal`객체와 `Animal`클래스를 표현한 그래프가 있습니다. ![](rabbit-animal-independent-animal.svg) -...And we would like to create another `class Rabbit`. +그리고 또 다른 `class Rabbit`을 만들고 싶다고 한다면... -As rabbits are animals, `Rabbit` class should be based on `Animal`, have access to animal methods, so that rabbits can do what "generic" animals can do. +토끼가 동물인것처럼, `Rabbit`클래스는 `Animal`클래스에 기반을 두어야 합니다. 동물 메서드에 접근할 수 있어야 하고 그렇게 해서 토끼도 "일반적으로" 동물들이 할 수 있는 것이 가능해야 합니다. -The syntax to extend another class is: `class Child extends Parent`. +다른 클래스를 확장하는 문법은 `class Child extends Parent` 입니다. -Let's create `class Rabbit` that inherits from `Animal`: +`Animal`클래스를 상속하는 `class Rabbit`을 만들어 보죠. ```js *!* @@ -51,27 +51,27 @@ class Rabbit extends Animal { let rabbit = new Rabbit("White Rabbit"); -rabbit.run(5); // White Rabbit runs with speed 5. -rabbit.hide(); // White Rabbit hides! +rabbit.run(5); // 하얀 토끼는 스피드 5로 달립니다. +rabbit.hide(); // 하얀 토끼는 숨었습니다! ``` -Object of `Rabbit` class have access to both `Rabbit` methods, such as `rabbit.hide()`, and also to `Animal` methods, such as `rabbit.run()`. +`Rabbit` 클래스의 객체는 `rabbit.hide()`와 `rabbit.run()`처럼 `Animal`과 `Rabbit`의 메서드 모두 사용할 수 있습니다. -Internally, `extends` keyword works using the good old prototype mechanics. It sets `Rabbit.prototype.[[Prototype]]` to `Animal.prototype`. So, if a method is not found in `Rabbit.prototype`, JavaScript takes it from `Animal.prototype`. +내부적으로, `extends` 키워드는 오래된 좋은 방법인 프로토타입 매커니즘을 사용합니다. extends 키워드는 `Rabbit.prototype.[[Prototype]]`을 `Animal.prototype`으로 설정합니다. 그래서 `Rabbit.prototype`에서 메서드를 찾을 수 없으면 자바스크립트는 `Animal.prototype`으로부터 가져옵니다. ![](animal-rabbit-extends.svg) -For instance, to find `rabbit.run` method, the engine checks (bottom-up on the picture): -1. The `rabbit` object (has no `run`). -2. Its prototype, that is `Rabbit.prototype` (has `hide`, but not `run`). -3. Its prototype, that is (due to `extends`) `Animal.prototype`, that finally has the `run` method. +예를 들면 `rabbit.run` 메서드를 찾기 위해서 자바스크립트 엔진은 다음을 체크합니다.(그림에서 밑에서 위로) +1. `rabbit` 객체(`run`을 가지고 있지 않음). +2. Rabbit의 프로토타입, `Rabbit.prototype`(`hide`는 있지만 `run`은 없음). +3. 객체의 프로토타입, 그것은 (`extends`키워드 때문에) 마침내 `run` 메서드를 가지고 있는 `Animal.prototype`이 됩니다. -As we can recall from the chapter , JavaScript itself uses prototypal inheritance for build-in objects. E.g. `Date.prototype.[[Prototype]]` is `Object.prototype`. That's why dates have access to generic object methods. + 챕터에서 살펴봤듯이, 자바스크립트는 내장 객체를 위해 같은 프로토타입을 상속합니다. 예를 들면, `Date.prototype.[[Prototype]]`은 `Object.prototype`이기 때문에 dates는 일반적인 객체의 메서드인 것이죠. -````smart header="Any expression is allowed after `extends`" -Class syntax allows to specify not just a class, but any expression after `extends`. +````smart header="`extends` 이후에 어떠한 표현형식이든 가능합니다" +클래스 문법은 오직 클래스만 정의할 수 있게 하는 것이 아니라 `extends` 후에 어떠한 표현 식이든 추가할 수 있습니다. -For instance, a function call that generates the parent class: +예를 들면, 아래의 함수처럼 부모 클래스를 생성한다고 해보겠습니다. ```js run function f(phrase) { @@ -86,34 +86,34 @@ class User extends f("Hello") {} new User().sayHi(); // Hello ``` -Here `class User` inherits from the result of `f("Hello")`. +위의 예제에서 `class User`는 `f("Hello")`의 결과를 상속합니다. -That may be useful for advanced programming patterns when we use functions to generate classes depending on many conditions and can inherit from them. +이런 방법은 함수를 사용하여 다양한 조건에 따라 클래스를 생성하고 상속이 요구되는 고급 프로그래밍 패턴을 사용할 때 유용합니다. ```` -## Overriding a method +## 메서드 오버라이딩 -Now let's move forward and override a method. By default, all methods that are not specified in `class Rabbit` are taken directly "as is" from `class Animal`. +이제 더 자세히 배워보겠습니다. 지금까지는 `Rabbit`이 `stop`메서드를 상속하고 `Animal`에서 온 `stop`메서드는 `this.speed = 0`으로 설정했었습니다. -But if we specify our own method in `Rabbit`, such as `stop()` then it will be used instead: +만약에 독립적인 `stop`메서드를 `Rabbit` 안에 정의할 수 있다면 다음과 같을 것입니다. ```js class Rabbit extends Animal { stop() { - // ...now this will be used for rabbit.stop() - // instead of stop() from class Animal + // ...여기에 정의될 메서드가 rabiit.stop()으로 호출될 것입니다. + // Animal 클래스의 stop() 메서드 대신에 말이죠. } } ``` -Usually we don't want to totally replace a parent method, but rather to build on top of it to tweak or extend its functionality. We do something in our method, but call the parent method before/after it or in the process. +...그러나 일반적으로 부모 메서드를 완전히 대체하기보다는 그 위에 기능을 추가해 수정하거나 확장하는 것이 좋습니다. 메서드에서 무언가를 수행하지만 처리 전후 또는 처리 중에 부모 메서드를 호출하기 때문이죠. -Classes provide `"super"` keyword for that. +이것을 위해 클래스는 `"super"`라는 키워드를 제공합니다. -- `super.method(...)` to call a parent method. -- `super(...)` to call a parent constructor (inside our constructor only). +- `super.method(...)`는 부모 클래스의 메서드를 호출합니다. +- `super(...)`는 부모의 생성자를 호출합니다.(상속받는 생성자의 안에서만 사용해야 합니다.) -For instance, let our rabbit autohide when stopped: +예를 들어 아래의 rabbit에서 stop 되었을 때 어떻게 자동으로 hide를 호출하는지 알아보겠습니다. ```js run class Animal { @@ -142,52 +142,52 @@ class Rabbit extends Animal { *!* stop() { - super.stop(); // call parent stop - this.hide(); // and then hide + super.stop(); // 부모의 stop을 호출합니다. + this.hide(); // 그리고 hide 메서드를 실행합니다. } */!* } let rabbit = new Rabbit("White Rabbit"); -rabbit.run(5); // White Rabbit runs with speed 5. -rabbit.stop(); // White Rabbit stands still. White rabbit hides! +rabbit.run(5); // 하얀 토끼는 스피드 5로 달립니다. +rabbit.stop(); // 하얀 토끼는 그대로 서 있습니다. 그리고 숨었습니다! ``` -Now `Rabbit` has the `stop` method that calls the parent `super.stop()` in the process. +여기서 `Rabbit`은 부모 클래스로부터 `super.stop()`메서드를 호출하는 `stop` 메서드를 가지고 있습니다. -````smart header="Arrow functions have no `super`" -As was mentioned in the chapter , arrow functions do not have `super`. +````smart header="화살표 함수는 `super`가 없습니다." + 챕터에서 언급했듯이, 화살표 함수는 `super`를 가지고 있지 않습니다. -If accessed, it's taken from the outer function. For instance: +만약에 부모 함수에 접근 가능하다면 외부의 함수에서 가져왔을 겁니다. 아래 예제를 보면 알 수 있습니다. ```js class Rabbit extends Animal { stop() { - setTimeout(() => super.stop(), 1000); // call parent stop after 1sec + setTimeout(() => super.stop(), 1000); // 부모의 stop을 1초 후에 호출합니다. } } ``` -The `super` in the arrow function is the same as in `stop()`, so it works as intended. If we specified a "regular" function here, there would be an error: +화살표 함수 안의 `super`는 `stop()` 안에서 쓰인 것과 같아서 의도한 대로 동작할 것입니다. 그런데 만약에 "정규" 함수를 여기에 정의한다면, 에러가 발생할 것입니다. ```js -// Unexpected super +// 예상하지 못한 super setTimeout(function() { super.stop() }, 1000); ``` ```` -## Overriding constructor +## 생성자 오버라이딩 -With constructors it gets a little bit tricky. +생성자를 오버라이딩 하는 데에는 기술이 조금 필요합니다. -Till now, `Rabbit` did not have its own `constructor`. +아직 `Rabbit`은 자신만의 `생성자(contructor)`를 가지고 있지 않았습니다. -According to the [specification](https://tc39.github.io/ecma262/#sec-runtime-semantics-classdefinitionevaluation), if a class extends another class and has no `constructor`, then the following "empty" `constructor` is generated: +[자바스크립트 명세서](https://tc39.github.io/ecma262/#sec-runtime-semantics-classdefinitionevaluation)에 따르면 만약 클래스가 다른 클래스를 확장하고 생성된 클래스가 `생성자`를 가지고 있지 않다면, "비어있는" `생성자`를 생성합니다. ```js class Rabbit extends Animal { - // generated for extending classes without own constructors + // 자신의 생성자가 없는 상속받는 클래스를 생성합니다. *!* constructor(...args) { super(...args); @@ -196,9 +196,9 @@ class Rabbit extends Animal { } ``` -As we can see, it basically calls the parent `constructor` passing it all the arguments. That happens if we don't write a constructor of our own. +위에 예시에서처럼 해당 클래스의 생성자를 명시하지 않을 때는 기본적으로 부모의 `생성자`를 모든 인수와 함께 전달합니다. -Now let's add a custom constructor to `Rabbit`. It will specify the `earLength` in addition to `name`: +이제 `Rabbit`에 특수한 생성자를 추가해 보겠습니다. 생성자에서 `earLength`를 정의하고 `name`을 추가할 것입니다. ```js run class Animal { @@ -223,29 +223,29 @@ class Rabbit extends Animal { } *!* -// Doesn't work! -let rabbit = new Rabbit("White Rabbit", 10); // Error: this is not defined. +// 아래의 코드는 동작하지 않습니다! +let rabbit = new Rabbit("White Rabbit", 10); // 에러: 정의되지 않음.. */!* ``` -Whoops! We've got an error. Now we can't create rabbits. What went wrong? +이런! 에러가 발생합니다. 이제 rabbits를 생성할 수 없네요. 무엇이 잘못된 것일까요? -The short answer is: constructors in inheriting classes must call `super(...)`, and (!) do it before using `this`. +간단히 설명하자면 상속받은 클래스 안의 생성자는 `this`를 사용하기 전에 `super(...)`를 반드시 호출해야 합니다. -...But why? What's going on here? Indeed, the requirement seems strange. +...그런데 왜 그래야 할까요? 무슨 일이 일어나고 있는 걸까요? 결국, 이런 요구사항은 뭔가 이상해 보입니다. -Of course, there's an explanation. Let's get into details, so you'll really understand what's going on. +당연히 `super(...)`를 반드시 호출해야 하는 상황을 설명할 수 있습니다. 자세히 보면 무슨 일이 일어나는지 이해할 수 있을 것입니다. -In JavaScript, there's a distinction between a "constructor function of an inheriting class" and all others. In an inheriting class, the corresponding constructor function is labeled with a special internal property `[[ConstructorKind]]:"derived"`. +자바스크립트에서는 "상속하는 클래스의 생성자 함수"와 다른 모든 클래스 사이에는 구분이 있습니다. 상속 클래스에서 상응하는 생성자 함수는 특별한 내부 속성 `[[ConstructorKind]]:"derived"`로 레이블이 지정되어 있습니다. -The difference is: +다른 점은 다음과 같습니다. -- When a normal constructor runs, it creates an empty object and assigns it to `this`. -- But when a derived constructor runs, it doesn't do this. It expects the parent constructor to do this job. +- 일반 생성자가 실행되면 빈 객체를 `this`로 만들고 계속 진행합니다. +- 그러나 파생된 생성자가 실행될 때는 빈 객체를 `this`로 만들고 진행하지 않습니다. 부모 생성자가 이러한 작업을 수행할 것으로 기대합니다. -So if we're making a constructor of our own, then we must call `super`, because otherwise the object for `this` won't be created. And we'll get an error. +그래서 만약 생성자를 생성한다면, `super`를 호출해야 합니다. 그렇지 않으면 `this`를 빈 객체로 생성할 것이기 때문입니다. 그래서 오류가 발생한 것입니다. -For `Rabbit` constructor to work, it needs to call `super()` before using `this`, like here: +`Rabbit`이 작동하려면, 다음과 같이 `this`를 사용하기 전에 `super()`를 호출해야 합니다. ```js run class Animal { @@ -281,25 +281,25 @@ alert(rabbit.earLength); // 10 ## Super: internals, [[HomeObject]] -```warn header="Advanced information" -If you're reading the tutorial for the first time - this section may be skipped. +```warn header="추가 정보" +만약에 이 튜토리얼을 처음 보는 것이라면 이번 파트는 넘어가도 됩니다. -It's about the internal mechanisms behind inheritance and `super`. +다음 내용은 상속과 `super`의 내부 매커니즘에 대한 것입니다. ``` -Let's get a little deeper under the hood of `super`. We'll see some interesting things along the way. +`super`의 숨겨진 부분을 조금 더 깊숙이 들어가 보겠습니다. 흥미로운 것들을 보게 될 것입니다. -First to say, from all that we've learned till now, it's impossible for `super` to work at all! +먼저 지금까지 배운 모든 것에서, `super`가 전혀 작동하지 않는다는 것을 명심하세요! -Yeah, indeed, let's ask ourselves, how it should technically work? When an object method runs, it gets the current object as `this`. If we call `super.method()` then, the engine needs to get the `method` from the prototype of the current object. But how? +실제 기술적으로 어떻게 super가 작동 할 수 있는지 스스로 답해보세요. 객체 메서드가 실행되면 현재 객체를 `this`로 가져옵니다. `super.method()`를 호출하면 현재 객체의 프로토타입에서 `method`를 가져와야 합니다. 그런데 어떻게 하면 그렇게 할까요? -The task may seem simple, but it isn't. The engine knows the current object `this`, so it could get the parent `method` as `this.__proto__.method`. Unfortunately, such a "naive" solution won't work. +작업은 단순해 보일 수도 있지만 그렇지 않습니다. 엔진은 현재 객체 `this`를 알고 있으므로, 부모 `method`를 `this.__ proto __. method`로 얻을 수 있을 것 같지만 불행히도 이러한 "간단한" 해결책은 효과가 없습니다. -Let's demonstrate the problem. Without classes, using plain objects for the sake of simplicity. +여기에 어떠한 문제가 있는지 설명해 보겠습니다. 클래스가 없으면 단순성을 위해 일반 오브젝트를 사용합니다. -You may skip this part and go below to the `[[HomeObject]]` subsection if you don't want to know the details. That won't harm. Or read on if you're interested in understanding things in-depth. +만약에 더 자세히 알고 싶지 않다면 아래의 `[[HomeObject]]`부분은 넘어가도 됩니다. 모른다고 문제 될 것은 없으니 더 자세히 알고 싶은 분만 읽어보시길 바랍니다. -In the example below, `rabbit.__proto__ = animal`. Now let's try: in `rabbit.eat()` we'll call `animal.eat()`, using `this.__proto__`: +아래 `rabbit.__ proto__ = animal` 예시를 보면, `rabbit.eat ()`에서 `this.__ proto__`를 사용하여`animal.eat()`를 호출하는 것을 시도합니다. ```js run let animal = { @@ -314,7 +314,7 @@ let rabbit = { name: "Rabbit", eat() { *!* - // that's how super.eat() could presumably work + // super.eat()이 작동할 방법일 것입니다. this.__proto__.eat.call(this); // (*) */!* } @@ -323,11 +323,11 @@ let rabbit = { rabbit.eat(); // Rabbit eats. ``` -At the line `(*)` we take `eat` from the prototype (`animal`) and call it in the context of the current object. Please note that `.call(this)` is important here, because a simple `this.__proto__.eat()` would execute parent `eat` in the context of the prototype, not the current object. +`(*)`줄에서는 prototype (`animal`)에서 `eat`을 가져와서 현재 객체의 컨텍스트에서 호출합니다. 간단한 `this.__ proto __.eat()`은 현재 객체가 아니라 프로토타입의 맥락에서 부모의 `eat`을 실행할 것이기 때문에 `.call(this)`이 중요하게 사용되었습니다. -And in the code above it actually works as intended: we have the correct `alert`. +그래서 위의 코드는 실제 의도 한 대로 작동합니다. `경고` 문구가 올바르게 출력됩니다. -Now let's add one more object to the chain. We'll see how things break: +이제 하나의 객체를 체인에 추가해 봅시다. 상황이 어떻게 잘못되는지 볼 수 있습니다. ```js run let animal = { @@ -340,7 +340,7 @@ let animal = { let rabbit = { __proto__: animal, eat() { - // ...bounce around rabbit-style and call parent (animal) method + // ...rabbit-style 로 바운싱해서 부모(animal)의 메서드를 호출 this.__proto__.eat.call(this); // (*) } }; @@ -348,7 +348,7 @@ let rabbit = { let longEar = { __proto__: rabbit, eat() { - // ...do something with long ears and call parent (rabbit) method + // ...long ears 에서 부모(rabbit)의 메서드를 호출 this.__proto__.eat.call(this); // (**) } }; @@ -358,49 +358,49 @@ longEar.eat(); // Error: Maximum call stack size exceeded */!* ``` -The code doesn't work anymore! We can see the error trying to call `longEar.eat()`. +코드가 이제는 작동하지 않습니다! `longEar.eat()`를 호출하는 동안 오류를 볼 수 있습니다. -It may be not that obvious, but if we trace `longEar.eat()` call, then we can see why. In both lines `(*)` and `(**)` the value of `this` is the current object (`longEar`). That's essential: all object methods get the current object as `this`, not a prototype or something. +정확하게 보이지 않을 수도 있습니다만 `longEar.eat()` 호출을 추적하면 그 이유를 알 수 있습니다. `(*)` 와 `(**)` 두 줄에서 `this`의 값은 현재 객체(`longEar`)입니다. 이것은 필수입니다. 그래서 모든 객체 메서드는 현재의 객체를 프로토타입이나 무언가가 아닌 `this`로 얻습니다. -So, in both lines `(*)` and `(**)` the value of `this.__proto__` is exactly the same: `rabbit`. They both call `rabbit.eat` without going up the chain in the endless loop. +그래서`(*)`와`(**)`두 줄에서 `this.__ proto__`의 값은 정확히 `rabbit`으로 동일합니다. 그래서 둘 다 무한 루프 속에서 `rabbit.eat`을 호출하려고 합니다. -Here's the picture of what happens: +아래 그림에서 무슨 일이 일어나고 있는지 이해를 도와줄 것입니다. ![](this-super-loop.svg) -1. Inside `longEar.eat()`, the line `(**)` calls `rabbit.eat` providing it with `this=longEar`. +1. `longEar.eat()` 내부에서 `(**)`는 `this = longEar`를 가지고 있는 `rabbit.eat`을 호출합니다. ```js - // inside longEar.eat() we have this = longEar + // longEar.eat() 내부에서는 this = longEar 입니다. this.__proto__.eat.call(this) // (**) - // becomes + // 위의 코드는 다음과 같고 longEar.__proto__.eat.call(this) - // that is + // longEar의 prototype은 rabbit이므로 아래와 같이 작성할 수 있습니다. rabbit.eat.call(this); ``` -2. Then in the line `(*)` of `rabbit.eat`, we'd like to pass the call even higher in the chain, but `this=longEar`, so `this.__proto__.eat` is again `rabbit.eat`! +2. 그런 다음 `rabbit.eat`의 `(*)`줄에서 더 위 단계에 호출을 전달하려고 합니다. 그러나 `this=longEar`이므로 `this.__ proto __.eat`은 다시 `rabbit.eat` 입니다! ```js - // inside rabbit.eat() we also have this = longEar + // rabbit.eat() 내부에서 다시 this = longEar 입니다. this.__proto__.eat.call(this) // (*) - // becomes + // 다음과 같고 longEar.__proto__.eat.call(this) - // or (again) + // 또는 (또다시) 이렇게 됩니다. rabbit.eat.call(this); ``` -3. ...So `rabbit.eat` calls itself in the endless loop, because it can't ascend any further. +3. ...그래서 `rabbit.eat`은 더는 올라가서 호출할 수가 없어 스스로를 부르기 때문에 무한 루프가 됩니다. -The problem can't be solved by using `this` alone. +이런 문제는 `this`를 독립적으로 사용해서는 해결할 수 없습니다. ### `[[HomeObject]]` -To provide the solution, JavaScript adds one more special internal property for functions: `[[HomeObject]]`. +해결책을 제공하기 위해 자바스크립트는 함수를 위한 `[[HomeObject]]`라는 하나의 특별한 내부 속성을 추가합니다. -When a function is specified as a class or object method, its `[[HomeObject]]` property becomes that object. +함수가 클래스나 객체 메서드로 지정되면, 그것의 [[HomeObject]] 속성은 그 객체가 됩니다. -Then `super` uses it to resolve the parent prototype and its methods. +그런 다음 `super`는 [[HomeObject]]를 사용하여 부모 프로토타입과 그 메서드를 결정합니다. -Let's see how it works, first with plain objects: +먼저 일반 객체로 어떻게 작동하는지 살펴보겠습니다. ```js run let animal = { @@ -427,22 +427,22 @@ let longEar = { }; *!* -// works correctly +// 올바르게 작동합니다. longEar.eat(); // Long Ear eats. */!* ``` -It works as intended, due to `[[HomeObject]]` mechanics. A method, such as `longEar.eat`, knows its `[[HomeObject]]` and takes the parent method from its prototype. Without any use of `this`. +`[[HomeObject]]`의 메커니즘 때문에 의도한 대로 작동합니다. `longEar.eat`과 같은 메서드는 그것의 `[[HomeObject]]`를 알고 프로토타입으로부터 부모 메서드를 취합니다. `this`를 사용하지 않고도 말이죠. -### Methods are not "free" +### "자유"롭지 않은 메서드 -As we've known before, generally functions are "free", not bound to objects in JavaScript. So they can be copied between objects and called with another `this`. +이전에 알려진 것처럼 일반적으로 함수는 "자유"이며 자바스크립트의 객체에 바인딩 되지 않습니다. 그래서 함수들은 객체 간에 복사될 수 있고 또 다른 `this`로 호출될 수 있습니다. -The very existance of `[[HomeObject]]` violates that principle, because methods remember their objects. `[[HomeObject]]` can't be changed, so this bond is forever. +`[[HomeObject]]`의 존재는 메서드가 객체를 기억하기 때문에 위와 같은 원리를 위반합니다. `[[HomeObject]]`는 변경할 수 없으므로 함수와 객체 간의 유대감은 영원합니다. -The only place in the language where `[[HomeObject]]` is used -- is `super`. So, if a method does not use `super`, then we can still consider it free and copy between objects. But with `super` things may go wrong. +`[[HomeObject]]`가 사용되는 언어의 유일한 장소는 `super` 입니다. 따라서 메서드가 `super` 를 사용하지 않는다면, 여전히 함수들을 자유롭게 다룰 수 있고 객체들 사이에서 복사 할 수 있습니다. 하지만 `super`로도 상황이 잘못될 수 있습니다. -Here's the demo of a wrong `super` result after copying: +다음은 잘못된 `super`의 사용예시입니다. ```js run let animal = { @@ -478,28 +478,28 @@ tree.sayHi(); // I'm an animal (?!?) */!* ``` -A call to `tree.sayHi()` shows "I'm an animal". Definitevely wrong. +`tree.sayHi()`를 호출하면 "I'm an animal"을 출력합니다. 이것은 확실히 잘못된 결과입니다. -The reason is simple: -- In the line `(*)`, the method `tree.sayHi` was copied from `rabbit`. Maybe we just wanted to avoid code duplication? -- Its `[[HomeObject]]` is `rabbit`, as it was created in `rabbit`. There's no way to change `[[HomeObject]]`. -- The code of `tree.sayHi()` has `super.sayHi()` inside. It goes up from `rabbit` and takes the method from `animal`. +잘못된 결과가 나온 이유는 간단합니다. +- `(*)` 줄에서 `tree.sayHi` 메서드는`rabbit`에서 복사되었습니다. 어쩌면 단지 코드 중복을 피하고 싶었던 걸까요? +- 그래서 tree 객체의 `[[HomeObject]]`는 rabbit 안에 만들어졌기 때문에 `rabbit`입니다. `[[HomeObject]]`를 ​​변경할 방법은 없습니다. +- `tree.sayHi()`의 코드는 `super.sayHi()`를 내부에 가지고 있습니다. `rabbit`에서 부모객체인 `animal`에서 가져온 것이죠. -Here's the diagram of what happens: +아래의 다이어그램은 어떻게 진행되는지 보여주고 있습니다. ![](super-homeobject-wrong.svg) -### Methods, not function properties +### 메서드는 함수의 프로퍼티가 아닙니다. -`[[HomeObject]]` is defined for methods both in classes and in plain objects. But for objects, methods must be specified exactly as `method()`, not as `"method: function()"`. +`[[HomeObject]]`는 클래스와 일반 객체 모두에서 메서드에 대해 정의됩니다. 그러나 객체의 경우, 메서드는 `method()`처럼 정확히 지정되어야 합니다. 예를 들면 `"메서드: function() "`같이 말이죠. -The difference may be non-essential for us, but it's important for JavaScript. +이러한 차이는 필수는 아니지만, 자바스크립트에서는 중요합니다. -In the example below a non-method syntax is used for comparison. `[[HomeObject]]` property is not set and the inheritance doesn't work: +아래 예제에서는 비 메서드 구문을 사용하여 비교해 보겠습니다. `[[HomeObject]]`프로퍼티로 설정되지 않고 상속되지 않습니다. ```js run let animal = { - eat: function() { // intentially writing like this instead of eat() {... + eat: function() { // 짧은 문법으로는 eat() {...} 이 되어야 합니다. // ... } }; @@ -512,21 +512,21 @@ let rabbit = { }; *!* -rabbit.eat(); // Error calling super (because there's no [[HomeObject]]) +rabbit.eat(); // super 호출 에러 (왜냐하면 [[HomeObject]]가 없기 때문입니다.) */!* ``` -## Summary +## 요약 -1. To extend a class: `class Child extends Parent`: - - That means `Child.prototype.__proto__` will be `Parent.prototype`, so methods are inherited. -2. When overriding a constructor: - - We must call parent constructor as `super()` in `Child` constructor before using `this`. -3. When overriding another method: - - We can use `super.method()` in a `Child` method to call `Parent` method. -4. Internals: - - Methods remember their class/object in the internal `[[HomeObject]]` property. That's how `super` resolves parent methods. - - So it's not safe to copy a method with `super` from one object to another. +1. 클래스를 확장하는 법: `class Child extends Parent` + - 이 문법은 `Child.prototype.__proto__`가 `Parent.prototype`되는 것을 의미하기 때문에 메서드가 상속됩니다. +2. 생성자를 오버라이딩 할 때는 + - 부모의 생성자를 `super()`로 `this`가 사용되기 전에 `자식`의 생성자 안에서 호출해야 합니다. +3. 다른 메서드를 오버라이딩 할 때는 + - `부모`의 메서드를 호출할 때 `super.method()`로 `자식` 안에서 사용할 수 있습니다. +4. Internals + - 메서드는 내부 `[[HomeObject]]` 프로퍼티에 그것의 클래스와 오브젝트를 기억합니다. `[[HomeObject]]`는 어떻게 `super`가 부모 메서드를 호출할 수 있게 하는가에 대한 문제를 해결하는 방법입니다. + - 그래서 메서드를 `super`와 함께 한 객체에서 다른 객체로 복사하는 것은 안전하지 않습니다. -Also: -- Arrow functions don't have own `this` or `super`, so they transparently fit into the surrounding context. +또한 +- 화살표 함수들은 자신의 `this`나 `super`를 가지고 있지 않습니다. 그래서 주변 컨텍스트에 영향 없이 투명하게 사용할 수 있습니다.