Skip to content
Open
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
먼저, 해당 코드가 왜 작동하지 않는지 살펴봐야 합니다.

코드를 실행하면 이유를 찾을 수 있습니다. 상속 받는 클래스의 생성자는 `super()`를 반드시 호출해야 합니다. 그렇지 않으면 `"this"`가 '정의'되지 않습니다.
코드를 실행하면 이유를 찾을 수 있습니다. 상속받는 클래스의 생성자는 `super()`를 반드시 호출해야 합니다. 그렇지 않으면 `"this"`가 '정의'되지 않습니다.

수정한 코드는 다음과 같습니다.

Expand All @@ -21,22 +21,14 @@ alert( rabbit.hasOwnProperty('name') ); // true

그런데 이게 끝이 아닙니다.

<<<<<<< HEAD
위와 같이 수정 해도, 여전히 `"class Rabbit extends Object"`와 `class Rabbit`는 다른점이 있습니다.
=======
Even after the fix, there's still an important difference between `"class Rabbit extends Object"` and `class Rabbit`.
>>>>>>> upstream/master
위와 같이 수정해도, 여전히 `"class Rabbit extends Object"`와 `class Rabbit` 사이에는 중요한 차이가 있습니다.

아시다시피 'extends' 문법은 두 개의 프로토타입을 설정합니다.

1. 생성자 함수의 `"prototype"` 사이(일반 메서드용)
2. 생성자 함수 자체 사이(정적 메서드용)

<<<<<<< HEAD
예시의 `class Rabbit extends Object`는 다음과 같은 관계를 만들죠.
=======
In the case of `class Rabbit extends Object` it means:
>>>>>>> upstream/master
예시의 `class Rabbit extends Object`는 다음과 같은 관계를 만듭니다.

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

<<<<<<< HEAD
따라서 `Rabbit`은 아래와 같이 `Rabbit`을 통해 `Object`의 정적 메서드에 접근할 수 있습니다.
=======
So `Rabbit` now provides access to the static methods of `Object` via `Rabbit`, like this:
>>>>>>> upstream/master

```js run
class Rabbit extends Object {}
Expand Down Expand Up @@ -79,11 +67,8 @@ alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error

이런 이유 때문에 `Rabbit`에서 `Object`의 정적 메서드를 사용할 수 없습니다.

<<<<<<< HEAD
한편, `Function.prototype`은 `call`, `bind` 등의 '일반' 함수 메서드를 가집니다. 내장 객체, `Object`의 생성자는 `Object.__proto__ === Function.prototype` 관계를 갖기 때문에 `Function.prototype`에 정의된 일반 함수 메서드는 두 경우 모두에 사용할 수 있습니다.
=======
By the way, `Function.prototype` also 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`.
>>>>>>> upstream/master
한편, `Function.prototype`은 `call`, `bind` 등의 '일반' 함수 메서드를 가집니다. 내장 객체 `Object`의 생성자는 `Object.__proto__ === Function.prototype` 관계를 갖기 때문에 `Function.prototype`에 정의된 일반 함수 메서드는 두 경우 모두에 사용할 수 있습니다.


이해를 돕기 위한 그림:

Expand Down
62 changes: 12 additions & 50 deletions 1-js/09-classes/03-static-properties-methods/article.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@

# 정적 메서드와 정적 프로퍼티

<<<<<<< HEAD
`"prototype"`이 아닌 클래스 함수 자체에 메서드를 설정할 수도 있습니다. 이런 메서드를 *정적(static)* 메서드라고 부릅니다.

정적 메서드는 아래와 같이 클래스 안에서 `static` 키워드를 붙여 만들 수 있습니다.
=======
We can also assign a method to the class as a whole. Such methods are called *static*.

In a class declaration, they are prepended by `static` keyword, like this:
>>>>>>> upstream/master

```js run
class User {
Expand Down Expand Up @@ -37,17 +31,10 @@ User.staticMethod(); // true

`User.staticMethod()`가 호출될 때 `this`의 값은 클래스 생성자인 `User` 자체가 됩니다(점 앞 객체).

<<<<<<< HEAD
정적 메서드는 어떤 특정한 객체가 아닌 클래스에 속한 함수를 구현하고자 할 때 주로 사용됩니다.

객체 `Article`이 여러 개 있고 이들을 비교해줄 함수가 필요하다고 가정해 봅시다. 가장 먼저 아래와 같이 `Article.compare`를 추가하는 방법이 떠오를 겁니다.
=======
Usually, static methods are used to implement functions that belong to the class as a whole, but not to any particular object of it.

For instance, we have `Article` objects and need a function to compare them.
정적 메서드는 어떤 특정한 객체가 아닌 클래스 전체에 속한 함수를 구현하고자 할 때 주로 사용됩니다.

A natural solution would be to add `Article.compare` static method:
>>>>>>> upstream/master
객체 `Article`이 여러 개 있고 이들을 비교해줄 함수가 필요하다고 가정해 봅시다.
가장 먼저 아래와 같이 `Article.compare` 정적 메서드를 추가하는 방법이 떠오를 겁니다.

```js run
class Article {
Expand Down Expand Up @@ -77,29 +64,19 @@ articles.sort(Article.compare);
alert( articles[0].title ); // CSS
```

<<<<<<< HEAD
여기서 `Article.compare`는 article(글)을 비교해주는 수단으로, 글 전체를 '위에서' 바라보며 비교를 수행합니다. `Article.compare`이 글 하나의 메서드가 아닌 클래스의 메서드여야 하는 이유가 여기에 있습니다.
여기서 `Article.compare`는 article(글)을 비교해주는 수단으로, 글 전체를 '위에서' 바라보며 비교를 수행합니다. `Article.compare`가 글 하나의 메서드가 아닌 클래스의 메서드여야 하는 이유가 여기에 있습니다.

이번에 살펴볼 예시는 '팩토리' 메서드를 구현한 코드입니다. 다양한 방법을 사용해 조건에 맞는 article 인스턴스를 만들어야 한다고 가정해 봅시다.
=======
Here `Article.compare` method stands "above" articles, as a means to compare them. It's not a method of an article, but rather of the whole class.
이번에 살펴볼 예시는 소위 '팩토리(factory)' 메서드를 구현한 코드입니다.

Another example would be a so-called "factory" method.

Let's say, we need multiple ways to create an article:
>>>>>>> upstream/master
다양한 방법을 사용해 조건에 맞는 article 인스턴스를 만들어야 한다고 가정해 봅시다.

1. 매개변수(`title`, `date` 등)를 이용해 관련 정보가 담긴 article 생성
2. 오늘 날짜를 기반으로 비어있는 article 생성
3. 기타 등등

첫 번째 방법은 생성자를 사용해 구현할 수 있습니다. 두 번째 방법은 클래스에 정적 메서드를 만들어 구현할 수 있습니다.

<<<<<<< HEAD
아래 `Article.createTodays()`같이 말이죠.
=======
Such as `Article.createTodays()` here:
>>>>>>> upstream/master

```js run
class Article {
Expand All @@ -126,32 +103,21 @@ alert( article.title ); // Today's digest
정적 메서드는 아래 예시와 같이 항목 검색, 저장, 삭제 등을 수행해주는 데이터베이스 관련 클래스에도 사용됩니다.

```js
<<<<<<< HEAD
// Article은 article을 관리해주는 특별 클래스라고 가정합시다.
// article 삭제에 쓰이는 정적 메서드
Article.remove({id: 12345});
```

## 정적 프로퍼티
=======
// assuming Article is a special class for managing articles
// static method to remove the article by id:
Article.remove({id: 12345});
```

````warn header="Static methods aren't available for individual objects"
Static methods are callable on classes, not on individual objects.

E.g. such code won't work:
````warn header="정적 메서드는 클래스에서 호출할 수 있으며, 개별 객체에서는 호출할 수 없습니다."
정적 메서드는 개별 객체가 아닌 클래스 자체에서 호출할 수 있습니다. 즉, 객체 하나에 속한 메서드가 아니라 클래스 자체에 속한 메서드입니다.
예를 들어 아래 코드는 동작하지 않습니다.

```js
// ...
article.createTodays(); /// Error: article.createTodays is not a function
```
````

## Static properties
>>>>>>> upstream/master
## 정적 프로퍼티

[recent browser=Chrome]

Expand All @@ -171,11 +137,7 @@ alert( Article.publisher ); // Ilya Kantor
Article.publisher = "Ilya Kantor";
```

<<<<<<< HEAD
## 정적 프로퍼티와 메서드 상속
=======
## Inheritance of static properties and methods [#statics-and-inheritance]
>>>>>>> upstream/master
## 정적 프로퍼티와 메서드 상속 [#statics-and-inheritance]

정적 프로퍼티와 메서드는 상속됩니다.

Expand Down Expand Up @@ -224,7 +186,7 @@ rabbits[0].run(); // 검은 토끼가 속도 5로 달립니다.
alert(Rabbit.planet); // 지구
```

이제 `Rabbit.compare` 호출하면 `Animal.compare`가 호출됩니다.
이제 `Rabbit.compare` 호출하면 `Animal.compare`가 호출됩니다.

이게 가능한 이유는 프로토타입 때문입니다. 이미 예상하셨겠지만, `extends` 키워드는 `Rabbit`의 `[[Prototype]]`이 `Animal`을 참조하도록 해줍니다.

Expand Down
57 changes: 11 additions & 46 deletions 1-js/09-classes/04-private-protected-properties-methods/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

잠시 개발을 벗어나 현실 세계로 눈을 돌려, 내부 인터페이스와 외부 인터페이스 구분이 무엇을 의미하는지 알아봅시다.

일상생활에서 접하게 되는 기계들은 꽤 복잡한 구조로 되어 있습니다. 하지만 내부인터페이스와 외부 인터페이스가 구분되어있기 때문에 문제없이 기계를 사용할 수 있습니다.
일상생활에서 접하게 되는 기계들은 꽤 복잡한 구조로 되어 있습니다. 하지만 내부 인터페이스와 외부 인터페이스가 구분되어 있기 때문에 문제없이 기계를 사용할 수 있습니다.

## 실생활 예제

Expand All @@ -19,7 +19,7 @@

![](coffee-inside.jpg)

뭔가 디테일한 것들이 아주 많네요. 하지만 이 모든 것을 알지 못해도 커피 머신을 사용하는 데 지장이 없습니다.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

불필요한 , 같습니다.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

리뷰 감사합니다! 해당 문장을 맞춤법 검사기로 확인해 보니 '하지만, 이'로 교정하도록 안내되어 해당 규칙을 반영해 수정해 두었습니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

아 맞춤법 검사기에서 교정된거군요..!
프로젝트 규칙에 쉼표 사용을 자제하라고 해서 말씀드려봤습니다.
하지만 맞춤법 검사기가 교정했다면 맞춤법 검사기의 규칙을 따라가는게 맞는 것 같네요.😊

뭔가 디테일한 것들이 아주 많네요. 하지만, 이 모든 것을 알지 못해도 커피 머신을 사용하는 데 지장이 없습니다.

커피 머신은 꽤 믿음직한 기계입니다. 수년 간 사용할 수 있고, 중간에 고장이 나도 수리를 받으면 됩니다.

Expand All @@ -42,7 +42,7 @@

내부 인터페이스의 세부사항들은 서로의 정보를 이용하여 객체를 동작시킵니다. 발열 장치에 부착된 관을 통해 뜨거운 물이 이동하는 것처럼 말이죠.

그런데 커피 머신은 보호 커버에 둘러싸여 있기 때문에 보호 커버를 벗기지 않고는 커피머신 외부에서 내부로 접근할 수 없습니다. 밖에선 세부 요소를 알 수 없고, 접근도 불가능합니다. 내부 인터페이스의 기능은 외부 인터페이스를 통해야만 사용할 수 있습니다.
그런데 커피 머신은 보호 커버에 둘러싸여 있기 때문에 보호 커버를 벗기지 않고는 커피 머신 외부에서 내부로 접근할 수 없습니다. 밖에선 세부 요소를 알 수 없고, 접근도 불가능합니다. 내부 인터페이스의 기능은 외부 인터페이스를 통해야만 사용할 수 있습니다.

이런 특징 때문에 외부 인터페이스만 알아도 객체를 가지고 무언가를 할 수 있습니다. 객체 안이 어떻게 동작하는지 알지 못해도 괜찮다는 점은 큰 장점으로 작용합니다.

Expand Down Expand Up @@ -96,13 +96,9 @@ class CoffeeMachine {
_waterAmount = 0;

set waterAmount(value) {
<<<<<<< HEAD
if (value < 0) throw new Error("물의 양은 음수가 될 수 없습니다.");
=======
if (value < 0) {
value = 0;
}
>>>>>>> upstream/master
this._waterAmount = value;
}

Expand All @@ -119,19 +115,11 @@ class CoffeeMachine {
// 커피 머신 생성
let coffeeMachine = new CoffeeMachine(100);

<<<<<<< HEAD
// 물 추가
coffeeMachine.waterAmount = -10; // Error: 물의 양은 음수가 될 수 없습니다.
coffeeMachine.waterAmount = -10; // _waterAmount는 -10이 아닌 0이 됩니다.
```

이제 물의 양을 0 미만으로 설정하면 실패합니다.
=======
// add water
coffeeMachine.waterAmount = -10; // _waterAmount will become 0, not -10
```

Now the access is under control, so setting the water amount below zero becomes impossible.
>>>>>>> upstream/master
이제 접근을 통제할 수 있기 때문에 물의 양을 0 미만으로 설정하는 것은 불가능합니다.

## 읽기 전용 프로퍼티

Expand Down Expand Up @@ -173,11 +161,7 @@ class CoffeeMachine {
_waterAmount = 0;

*!*setWaterAmount(value)*/!* {
<<<<<<< HEAD
if (value < 0) throw new Error("물의 양은 음수가 될 수 없습니다.");
=======
if (value < 0) value = 0;
>>>>>>> upstream/master
this._waterAmount = value;
}

Expand All @@ -191,7 +175,7 @@ new CoffeeMachine().setWaterAmount(100);

다소 길어보이긴 하지만, 이렇게 함수를 선언하면 다수의 인자를 받을 수 있기 때문에 좀 더 유연합니다(위 예시에선 인자가 하나뿐이긴 하지만요).

반면 get, set 문법을 사용하면 코드가 짧아진다는 장점이 있습니다. 어떤걸 사용해야 한다는 규칙은 없으므로 원하는 방식을 선택해서 사용하세요.
반면 get, set 문법을 사용하면 코드가 짧아진다는 장점이 있습니다. 어떤 걸 사용해야 한다는 규칙은 없으므로 원하는 방식을 선택해서 사용하세요.
````

```smart header="protected 필드는 상속됩니다."
Expand All @@ -208,11 +192,7 @@ private 프로퍼티와 메서드는 제안(proposal) 목록에 등재된 문법

private 프로퍼티와 메서드는 `#`으로 시작합니다. `#`이 붙으면 클래스 안에서만 접근할 수 있습니다.

<<<<<<< HEAD
물 용량 한도를 나타내는 private 프로퍼티 `#waterLimit`과 남아있는 물의 양을 확인해주는 private 메서드 `#checkWater`를 구현해봅시다.
=======
For instance, here's a private `#waterLimit` property and the water-checking private method `#fixWaterAmount`:
Comment on lines -212 to -214
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

기존 문장도 괜찮아보이는데 취향에 따라 갈리는걸까요?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

리뷰 감사합니다! 영어 원문에서 메서드명이 #checkWater에서 #fixWaterAmount로 변경된 점을 확인하여, 해당 내용을 반영해 수정했습니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

감사합니다!

>>>>>>> upstream/master
예를 들어, 물 용량 한도를 나타내는 private 프로퍼티 `#waterLimit`과 물의 양을 보정해주는 private 메서드 `#fixWaterAmount`가 있습니다.

```js run
class CoffeeMachine {
Expand All @@ -221,15 +201,9 @@ class CoffeeMachine {
*/!*

*!*
<<<<<<< HEAD
#checkWater(value) {
if (value < 0) throw new Error("물의 양은 음수가 될 수 없습니다.");
if (value > this.#waterLimit) throw new Error("물이 용량을 초과합니다.");
=======
#fixWaterAmount(value) {
if (value < 0) return 0;
if (value > this.#waterLimit) return this.#waterLimit;
>>>>>>> upstream/master
}
*/!*

Expand All @@ -242,13 +216,8 @@ class CoffeeMachine {
let coffeeMachine = new CoffeeMachine();

*!*
<<<<<<< HEAD
// 클래스 외부에서 private에 접근할 수 없음
coffeeMachine.#checkWater(); // Error
=======
// can't access privates from outside of the class
// 클래스 외부에서 private에 접근할 수 없습니다.
coffeeMachine.#fixWaterAmount(123); // Error
>>>>>>> upstream/master
coffeeMachine.#waterLimit = 1000; // Error
*/!*
```
Expand All @@ -269,11 +238,7 @@ class CoffeeMachine {
}

set waterAmount(value) {
<<<<<<< HEAD
if (value < 0) throw new Error("물의 양은 음수가 될 수 없습니다.");
=======
if (value < 0) value = 0;
>>>>>>> upstream/master
this.#waterAmount = value;
}
}
Expand Down Expand Up @@ -322,12 +287,12 @@ class User {

객체 지향 프로그래밍에선 내부 인터페이스와 외부 인터페이스를 구분하는 것을 [캡슐화(encapsulation)]라는 용어를 사용해 설명합니다.

캡슐화는 이점은 다음과 같습니다.
캡슐화의 이점은 다음과 같습니다.

사용자가 자신의 발등을 찍지 않도록 보호
: 커피 머신를 함께 사용하는 개발팀이 있다고 상상해봅시다. "Best CoffeeMachine"이라는 회사에서 만든 이 커피 머신은 현재 잘 작동하고 있지만, 보호 커버가 없어서 내부 인터페이스가 노출되어있는 상황입니다.
: 커피 머신을 함께 사용하는 개발팀이 있다고 상상해봅시다. "Best CoffeeMachine"이라는 회사에서 만든 이 커피 머신은 현재 잘 작동하고 있지만, 보호 커버가 없어서 내부 인터페이스가 노출되어 있는 상황입니다.

교양있는 팀원들은 모두 설계 의도에 맞게 커피 머신을 사용합니다. 그런데 어느 날 John이라는 개발자가 자신의 능력을 과신하며 커피 머신 내부를 살짝 만지게 됩니다. 이틀 후, 커피 머신은 고장이 나버렸죠.
교양 있는 팀원들은 모두 설계 의도에 맞게 커피 머신을 사용합니다. 그런데 어느 날 John이라는 개발자가 자신의 능력을 과신하며 커피 머신 내부를 살짝 만지게 됩니다. 이틀 후, 커피 머신은 고장이 나버렸죠.

커피 머신이 고장 난 건 John의 잘못이라기보다는, 보호 커버를 없애고 John이 마음대로 조작하도록 내버려 둔 사람의 잘못입니다.

Expand Down
Loading