You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
return`${__super.sayHi.call(this)} how are you doing?`;
348
+
}
349
+
}
350
+
```
351
+
- 이렇게 동작하기 위해 메서드는 내부 슬롯 `[[HomeObject]]`를 가지며 자신을 바인딩하고 있는 객체를 가리킵니다.
352
+
- 단, ES6의 메서드 축약 표현으로 정의된 함수만 `[[HomeObject]]`를 갖습니다.
353
+
```js
354
+
constobj= {
355
+
// [[HomeObject]]를 갖습니다.
356
+
foo() {},
357
+
// [[HomeObject]]를 갖지 않습니다.
358
+
bar:function () {}
359
+
};
360
+
```
361
+
362
+
<br>
363
+
364
+
> 결국 super 참조를 의사 코드로 표현하면 아래와 같습니다.
365
+
```js
366
+
super=Object.getPrototypeOf([[HomeObject]])
367
+
```
368
+
1. `[[HomeObject]]`는 메서드 자신을 바인딩하고 있는 객체를 가리킵니다.
369
+
2. `[[HomeObject]]`를 통해 메서드 자신을 바인딩하고 있는 객체의 프로토타입을 찾을 수 있습니다.
370
+
3. 예로 들자면, Derived 클래스의 sayHi 메서드는 Derived.prototype에 바인딩되어 있습니다.
371
+
- 따라서 Derived 클래스의 sayHi 메서드의 `[[HomeObject]]`는 Derived.prototype이고, 이를 통해 Derived 클래스의 sayHi 메서드 내부의 super 참조가 Base.prototype으로 결정됩니다.
372
+
- 최종적으로 super.sayHi는 Base.prototype.sayHi를 가리키게 돼죠.
373
+
374
+
<br>
375
+
376
+
- 서브 클래의 정적 메서드 내에서 `super.메서드`는 슈퍼 클래스의 정적 메서드를 가리킵니다.
377
+
```js
378
+
// 슈퍼 클래스
379
+
classBase {
380
+
staticsayHi() {
381
+
return'Hi!';
382
+
}
383
+
}
384
+
385
+
// 서브 클래스
386
+
classDerivedextendsBase {
387
+
staticsayHi() {
388
+
// super.sayHi는 슈퍼 클래스의 정적 메서드를 가리킵니다.
389
+
return`${super.sayHi()} how are you doing?`;
390
+
}
391
+
}
392
+
393
+
console.log(Derived.sayHi()); // Hi! how are you doing?
394
+
```
395
+
396
+
<br>
397
+
398
+
### 상속 클래스의 인스턴스 생성 과정
399
+
> 클래스가 단독으로 인스턴스를 생성하는 과정보다 상속을 통해 인스턴스를 생성하는 과정이 더 복잡합니다.
400
+
401
+
서브 클래스가 new 연산자와 함께 호출되면 아래의 과정을 통해 인스턴스를 생성합니다.
402
+
403
+
- **서브 클래스의 super 호출**
404
+
- 자바스크립트 엔진은 클래스 평가 시 슈퍼 클래스와 서브 클래스를 구분하기 위해 `base` 또는 `derived`를 값으로 갖는 내부 슬롯 `[[ConstructorKind]]`를 갖습니다.
405
+
- 다른 클래스를 상속받지 않는 클래스는 내부 슬롯 `[[ConstructorKind]]`의 값이 `base`인 반면, 다른 클래스를 상속받는 클래스는 `derived`로 설정되며 이를 통해 동작이 구분됩니다.
406
+
- 상속받는 클래스가 new 연산자와 함께 호출되면 자신이 직접 인스턴스를 생성하지 않고 슈퍼 클래스에 인스턴스 생성을 위임합니다. 이게 바로 서브 클래스의 constructor에서 반드시 super를 호출해야 하는 이유죠.
407
+
- super가 호출되면 슈퍼 클래스의 constructor가 호출됩니다. 서브 클래스의 constructor 내부에 super 호출이 없다면 에러가 발생하는 이유는 실제 인스턴스를 생성하는 주체는 슈퍼 클래스이므로, 슈퍼 클래스의 constructor가 호출되지 않으면 인스턴스를 생성할 수 없기 때문이죠.
408
+
409
+
<br>
410
+
411
+
- **슈퍼 클래스의 인스턴스 생성과 this 바인딩**
412
+
- 슈퍼 클래스의 constructor 내부의 코드가 실행되기 이전에 암묵적으로 빈 객체를 생성하는데, 이 빈 객체가 클래스의 인스턴스입니다. 그리고 암묵적으로 생성된 빈 객체는 this에 바인딩 되죠. 결국 슈퍼 클래스의 constructor 내부의 this는 생성된 this를 가리키게 됩니다.
413
+
- 이 때 인스턴스는 슈퍼 클래스가 생성한 것이지만, new 연산자와 함게 호출된 클래스는 서브 클래스입니다. 즉, new 연산자와 함께 호출된 함수를 가리키는 `new.target`은 서브 클래스를 가리키며, 인스턴스는 `new.target`이 가리키는 서브 클래스가 생성한 것으로 처리됩니다.
414
+
- 결국 생성된 인스턴스의 프로토타입은 슈퍼 클래스의 prototype 프로퍼티가 가리키는 객체가 아니라 `new.target`이 가리키는 서브 클래스의 prototype 프로퍼티의 객체가 되는 것이죠.
415
+
416
+
<br>
417
+
418
+
- **슈퍼 클래스의 인스턴스 초기화**
419
+
- 슈퍼 클래스의 constructor가 실행되고 this에 바인딩된 인스턴스를 초기화합니다.
420
+
421
+
<br>
422
+
423
+
- **서브 클래스 constructor로의 복귀와 this 바인딩**
424
+
- super 호출이 종료되고 제어 흐름이 서브 클래스로 돌아오면 super가 반환한 인스턴스가 this에 바인딩됩니다.
425
+
- 서브 클래스는 별도의 인스턴스를 생성하지 않고 super가 반환한 인스턴스를 this에 바인딩하여 그대로 사용합니다.
426
+
- 이처럼 super가 호출되지 않으면 인스턴스가 생성되기는 커녕 this 바인딩도 이루어지지 않습니다. 서브 클래스의 constructor에서 super를 호출하기 전에는 this를 참조할 수 없는 이유죠.
427
+
428
+
<br>
429
+
430
+
- **서브클래스의 인스턴스 초기화**
431
+
- 서브 클래스의 constructor가 실행되고 this에 바인딩된 인스턴스에 프로퍼티를 추가합니다.
432
+
433
+
<br>
434
+
435
+
- **인스턴스 반환**
436
+
- 클래스의 모든 처리가 끝나면 완성된 인스턴스가 바인딩된 this가 암묵적으로 반환됩니다.
0 commit comments