Skip to content

Commit 4c78d17

Browse files
[프로토타입 상속] 개정
- 오타수정 - 좀 더 쉽게 풀이
1 parent 591d782 commit 4c78d17

File tree

1 file changed

+22
-21
lines changed
  • 1-js/08-prototypes/01-prototype-inheritance

1 file changed

+22
-21
lines changed

1-js/08-prototypes/01-prototype-inheritance/article.md

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
아래 예시처럼 특별한 이름인 `__proto__`을 사용하면 값을 설정할 수 있습니다.
2020

21-
```js run
21+
```js
2222
let animal = {
2323
eats: true
2424
};
@@ -44,7 +44,7 @@ rabbit.__proto__ = animal;
4444
4545
예시:
4646
47-
```js
47+
```js run
4848
let animal = {
4949
eats: true
5050
};
@@ -65,7 +65,7 @@ alert( rabbit.jumps ); // true
6565

6666
`(*)`로 표시한 줄에선 `animal``rabbit`의 프로토타입이 되도록 설정하였습니다.
6767

68-
`(**)`로 표시한 줄에서 `alert` 함수가 `rabbit.eats` 프로퍼티를 읽으려 했는데, `rabbit``eats`라는 프로퍼티가 없습니다. 이때 자바스크립트는 `[[Prototype]]`이 참조하고 있는 객체인 `animal`에서 `eats`를 얻어냅니다. 아래 그림을 밑에서부터 위로 살펴보세요.
68+
`(**)`로 표시한 줄에서 `alert` 함수가 `rabbit.eats` 프로퍼티를 읽으려 했는데, `rabbit``eats`라는 프로퍼티가 없습니다. 이때 자바스크립트는 `[[Prototype]]`이 참조하고 있는 객체인 `animal`에서 `eats`를 얻어냅니다. 다음 그림을 밑에서부터 위로 살펴보세요.
6969

7070
![](proto-animal-rabbit.svg)
7171

@@ -136,9 +136,9 @@ alert(longEar.jumps); // true (rabbit에서 상속받음)
136136
1. 순환 참조(circular reference)는 허용되지 않습니다. `__proto__`를 이용해 닫힌 형태로 다른 객체를 참조하면 에러가 발생합니다.
137137
2. `__proto__`의 값은 객체나 `null`만 가능합니다. 다른 자료형은 무시됩니다.
138138

139-
여기에 더하여 객체엔 오직 하나의 `[[Portotype]]`만 있을 수 있다는 당연한 제약도 있습니다. 객체는 두 개의 객체를 상속받지 못합니다.
139+
여기에 더하여 객체엔 오직 하나의 `[[Prototype]]`만 있을 수 있다는 당연한 제약도 있습니다. 객체는 두 개의 객체를 상속받지 못합니다.
140140

141-
## 쓸 때는 프로토타입을 사용하지 않습니다.
141+
## 프로토타입은 읽기 전용이다
142142

143143
프로토타입은 프로퍼티를 읽을 때만 사용합니다.
144144

@@ -167,13 +167,13 @@ rabbit.walk = function() {
167167
rabbit.walk(); // 토끼가 깡충깡충 뜁니다.
168168
```
169169

170-
`rabbit.walk()`를 호출하면 프로토타입에 있는 메서드가 실행되지 않고, 객체 `rabbit`에 추가한 메서드가 실행됩니다.
170+
`rabbit.walk()`를 호출하면 프로토타입에 있는 메서드가 실행되지 않고, 객체 `rabbit`직접 추가한 메서드가 실행됩니다.
171171

172172
![](proto-animal-rabbit-walk-2.svg)
173173

174-
그런데 접근자 프로퍼티(accessor property)는 setter 함수를 통해서 프로퍼티에 값을 할당하므로 이 규칙이 적용되지 않습니다. 접근자 프로퍼티에 값을 할당하는 것은 함수를 호출하는 것과 같기 때문입니다.
174+
그런데 접근자 프로퍼티(accessor property)는 setter 함수를 사용해 프로퍼티에 값을 할당하므로 접근자 프로퍼티에 값을 할당(`(**)`)하면 객체(`admin`)에 프로퍼티(`fullName`)가 추가되는게 아니라 setter 함수가 호출되면서 위 예시와는 조금 다르게 동작합니다.
175175

176-
아래 예시에서 `admin.fullName`이 의도한 대로 잘 작동하는 것을 확인할 수 있습니다.
176+
아래 예시에서 `admin.fullName`이 의도한 대로 잘 작동하는지 확인해 봅시다.
177177

178178
```js run
179179
let user = {
@@ -199,27 +199,28 @@ alert(admin.fullName); // John Smith (*)
199199
// setter 함수가 실행됩니다!
200200
admin.fullName = "Alice Cooper"; // (**)
201201

202-
alert(admin.fullName); // Alice Cooper , state of admin modified
203-
alert(user.fullName); // John Smith , state of user protected
202+
alert(admin.fullName); // Alice Cooper, setter에 의해 추가된 admin의 프로퍼티(name, surname)에서 값을 가져옴
203+
alert(user.fullName); // John Smith, 본래 user에 있었던 프로퍼티 값
204204
```
205205

206-
`(*)`로 표시한 줄에서 `admin.fullName`은 프로토타입(`user`)에 있는 getter 함수(`get fullName`)를 호출하고, `(**)`로 표시한 줄의 할당 연산은 프로토타입에 있는 setter 함수(`set fullName`)를 호출합니다.
206+
프로토타입 `user`엔 getter 함수 `get fullName`이 있기 때문에 `(*)`로 표시한 줄에선 `get fullName`이 호출되었습니다. 마찬가지로 프로토타입에 이미 setter 함수(`set fullName`)가 정의되어 있기 때문에 `(**)`로 표시한 줄의 할당 연산이 실행되면 객체 `user`에 프로퍼티가 추가되는게 아니라 프로토타입에 있는 setter 함수가 호출됩니다.
207+
207208

208-
## 'this'가 나타내는 것
209+
## this가 나타내는 것
209210

210211
위 예시를 보면 "`set fullName(value)` 본문의 `this`엔 어떤 값이 들어가지?"라는 의문을 가질 수 있습니다. "프로퍼티 `this.name``this.surname`에 값을 쓰면 그 값이 `user`에 저장될까, 아니면 `admin`에 저장될까?"라는 의문도 생길 수 있죠.
211212

212213
답은 간단합니다. `this`는 프로토타입에 영향을 받지 않습니다.
213214

214-
**메서드를 객체에서 호출했든 프로토타입에서 호출했든 상관없이 `this`는 언제나 `.` 앞에 있는 객체가 됩니다.**
215+
**메서드를 객체에서 호출했든 프로토타입에서 호출했든 상관없이 `this`는 언제나 `.` 앞에 있는 객체입니다.**
215216

216217
`admin.fullName=`으로 setter 함수를 호출할 때, `this``user`가 아닌 `admin`이 되죠.
217218

218219
객체 하나를 만들고 여기에 메서드를 많이 구현해 놓은 다음, 여러 객체에서 이 커다란 객체를 상속받게 하는 경우가 많기 때문에 이런 특징을 잘 알아두셔야 합니다. 상속받은 메서드를 사용하더라도 객체는 프로토타입이 아닌 자신의 상태를 수정합니다.
219220

220221
예시를 통해 좀 더 알아봅시다. '메서드 저장소' 역할을 하는 객체 `animal``rabbit`이 상속받게 해보겠습니다.
221222

222-
`rabbit.sleep()`을 호출하면 `this.isSleeping`객체 `rabbit`설정됩니다.
223+
`rabbit.sleep()`을 호출하면 객체 `rabbit``isSleeping`프로퍼티가 추가됩니다.
223224

224225
```js run
225226
// animal엔 다양한 메서드가 있습니다.
@@ -239,7 +240,7 @@ let rabbit = {
239240
__proto__: animal
240241
};
241242

242-
// rabbit의 프로퍼티 isSleeping을 true로 변경합니다.
243+
// rabbit에 새로운 프로퍼티 isSleeping을 추가하고 그 값을 true로 변경합니다.
243244
rabbit.sleep();
244245

245246
alert(rabbit.isSleeping); // true
@@ -250,9 +251,9 @@ alert(animal.isSleeping); // undefined (프로토타입에는 isSleeping이라
250251

251252
![](proto-animal-rabbit-walk-3.svg)
252253

253-
`rabbit` 말고도 `bird`, `snake` 등이 `animal`을 상속받는다고 해봅시다. 이 객체들도 `rabbit`처럼 `animal`에 구현된 메서드를 사용할 수 있겠죠. 이때 상속받은 메서드의 `this``animal`이 아닌 실제 메서드가 호출되는 시점의 점(`.`) 앞에 있는 객체가 됩니다. 따라서 `this`에 데이터를 쓰면 `animal`이 아닌 해당 객체의 상태가 변화합니다.
254+
`rabbit` 말고도 `bird`, `snake` 등이 `animal`을 상속받는다고 해봅시다. 이 객체들도 `rabbit`처럼 `animal`에 구현된 메서드를 사용할 수 있습니다. 이때 상속받은 메서드의 `this``animal`이 아닌 실제 메서드가 호출되는 시점의 점(`.`) 앞에 있는 객체가 됩니다. 따라서 `this`에 데이터를 쓰면 `animal`이 아닌 해당 객체의 상태가 변화합니다.
254255

255-
메서드는 공유되지만, 객체의 상태는 공유되지 않는다고 결론 내릴 수 있습니다.
256+
이를 통해 우리는 메서드는 공유되지만, 객체의 상태는 공유되지 않는다고 결론 내릴 수 있습니다.
256257

257258
## for..in 반복문
258259

@@ -281,7 +282,7 @@ for(let prop in rabbit) alert(prop); // jumps, eats
281282
*/!*
282283
```
283284

284-
[obj.hasOwnProperty(key)](mdn:js/Object/hasOwnProperty)를 이용하면 상속 프로퍼티를 순회 대상에서 제외할 수 있습니다. 이 내장 메서드는 `key`에 대응하는 프로퍼티가 상속 프로퍼티가 아니고 `obj`에 직접 구현되어있는 프로퍼티일 `true`를 반환합니다.
285+
[obj.hasOwnProperty(key)](mdn:js/Object/hasOwnProperty)를 이용하면 상속 프로퍼티를 순회 대상에서 제외할 수 있습니다. 이 내장 메서드는 `key`에 대응하는 프로퍼티가 상속 프로퍼티가 아니고 `obj`에 직접 구현되어있는 프로퍼티일 때만 `true`를 반환합니다.
285286

286287
`obj.hasOwnProperty(key)`를 응용하면 아래 예시에서처럼 상속 프로퍼티를 걸러낼 수 있고, 상속 프로퍼티만을 대상으로 무언가를 할 수도 있습니다.
287288

@@ -306,7 +307,7 @@ for(let prop in rabbit) {
306307
}
307308
```
308309

309-
위 예시의 상속 관계를 그림으로 나타내면 다음과 같습니다. `rabbit``animal`을, `animal``Object.prototype`을, `Object.prototype``null`을 상속받고 있습니다. `animal``Object.prototype`를 상속받는 이유는 객체 리터럴 방식으로 선언하였기 때문입니다.
310+
위 예시의 상속 관계를 그림으로 나타내면 다음과 같습니다. `rabbit``animal`을, `animal``Object.prototype`을, `Object.prototype``null`을 상속받고 있습니다. 참고로 `animal``Object.prototype`를 상속받는 이유는 `animal` 객체 리터럴 방식으로 선언하였기 때문입니다.
310311

311312
![](rabbit-animal-object.svg)
312313

@@ -327,7 +328,7 @@ for(let prop in rabbit) {
327328
- 자바스크립트의 모든 객체엔 숨김 프로퍼티 `[[Prototype]]`이 있는데, 이 프로퍼티는 객체나 `null`을 가리킵니다.
328329
- `obj.__proto__`를 사용하면 프로토타입에 접근할 수 있습니다. `__proto__``[[Prototype]]`의 getter·setter로 쓰이는데, 요즘엔 잘 쓰지 않습니다. 자세한 사항은 뒤쪽 챕터에서 다룰 예정입니다.
329330
- `[[Prototype]]`이 참조하는 객체를 '프로토타입'이라고 합니다.
330-
- `obj`에서 프로퍼티를 읽거나 메서드를 호출하려는데 해당하는 프로퍼티나 메서드가 없으면 자바스크립트는 프로토타입에서 프로퍼티나 메서드를 찾습니다.
331+
- 객체에서 프로퍼티를 읽거나 메서드를 호출하려는데 해당하는 프로퍼티나 메서드가 없으면 자바스크립트는 프로토타입에서 프로퍼티나 메서드를 찾습니다.
331332
- 접근자 프로퍼티가 아닌 데이터 프로퍼티를 다루고 있다면, 쓰기나 지우기와 관련 연산은 프로토타입을 통하지 않고 객체에 직접 적용됩니다.
332333
- 프로토타입에서 상속받은 `method`라도 `obj.method()`를 호출하면 `method` 안의 `this`는 호출 대상 객체인 `obj`를 가리킵니다.
333-
- `for..in` 반복문은 객체 자체에서 정의한 프로퍼티뿐만 아니라 상속 프로퍼티도 순회 대상에 포함합니다. 반면, 키-값과 관련된 내장 메서드 대부분은 상속 프로퍼티는 제외하고 객체 자체 프로퍼티만을 대상으로 동작합니다.
334+
- `for..in` 반복문은 객체 자체에서 정의한 프로퍼티뿐만 아니라 상속 프로퍼티도 순회 대상에 포함합니다. 반면, 키-값과 관련된 내장 메서드 대부분은 상속 프로퍼티는 제외하고 객체 자체 프로퍼티만을 대상으로 동작합니다.

0 commit comments

Comments
 (0)