Js- super
in Javascript
참고
[1] https://ko.javascript.info/class-inheritance
super
- 상속한 클래스의 메소드를 사용하고 싶을 때 super를 이용한다.
- 혹은 prototype 객체의 메소드를 사용하고 싶을 때 super를 이용한다.
class Animal{ constructor(){} stop(){ console.log("멈춰~!")} } class Rabbit extends Animal { stop(is_super){ if (is_super==true){ super.stop(); } else { console.log("stop~!"); } } } rabbit = new Rabbit(); rabbit.stop(is_super=true);- 화살표 함수에는 super 객체가 존재하지 않는다.
class Rabbit extends Animal{ stop(){ setTimeout(() => super.stop(), 1000); // Animal.stop() 메소드가 실행 setTimeout(function(){ super.stop(); }, 1000); // error: super는 undefined 이다. ps) super는 객체의 메소드, 클래스의 메소드에서만 defined된다. } }
super의 내부
- super의 역할을 보면 내부의 구현도 어느정도 쉬울 것 같지만 그렇지 않다
- 엔진은 현재 객체 this를 알기 때문에 this.proto.method를 통해 접근할 수 있을 것 같지만 이렇게 하면 오류가 존재한다.
- 그렇기 때문에 super를 this의 parent라고 생각하면 안된다.
- 아래 예시를 보면 eat 메소드를 오버라이딩해서 사용하고 있는데 prototype 객체의 메소드를 콜할 때는 원하는 바를 이루기 위해 call(this)를 통해 호출해야 한다. 그렇지 않으면 this는 prototype 객체를 가리킬테니
- 하지만 아래의 코드를 보면 rabbit.eat() 메소드 무한 루프에 빠지게 된다.
- 그렇기 때문에 super는 this만으로는 해결할 수 없다.
let animal = { name: "동물", eat() { console.log(`${this.name}이 먹이를 먹는다.`); } }; let rabbit = { __proto__: animal, name: "토끼", eat(){ this.__proto__.eat.call(this); } }; let longEar = { __proto__: rabbit, eat() { this.__proto__.eat.call(this); } }; longEar.eat(); // RangeError: Maximum call stack size exceeded
[[HomeObject]]
- super는 this를 통해 구현할 수 없다.
- [[HomeObject]]라는 함수 전용 특수 property를 이용하면 해결할 수 있다.
- [[HomeObject]]는 this처럼 해당 객체가 저장된다.
- super는 [[Homeobject]]를 이용해서 parent 객체를 찾고 처음 호출할 당시 자신의 객체(this)를 유지한다.
let animal = { name: "동물", eat() { // eat.[[HomeObject]] = animal console.log(`${this.name}이 먹이를 먹는다.`); // this는 longEar로 들어간다. } }; let rabbit = { __proto__: animal, name: "토끼", eat(){ // eat.[[HomeObject]] = rabbit super.eat(); } }; let longEar = { __proto__: rabbit, eat() { // eat.[[HomeObject]] = longEar super.eat(); } }; longEar.eat(); // this는 longEar가 들어간다. super가 HomeObject를 통해 그렇게 되도록 유지한다.- [[HomeObject]] property는 변경할 수 없다. 그렇기 때문에 함수(객체)가 생성될 때 고정되어 정해진다.
- 하지만 자바스크립트에서 함수나 객체는 자유롭게 복사되거나 바인딩 객체가 변할 수도 있다.
- [[HomeObject]] property는 super 내부에서만 유효하다. 하지만 복사와 바인딩을 super와 함께사용한다면 문제가 될 수 있다.
- 아래의 코드를 보면 tree.sayHi() 메소드는 rabbit.sayHi() 메소드를 복사해 쓴다.
- 하지만 복사한 메소드는 rabbit에 의해 생성된 함수이므로 함수의 [[HomeObject]] property는 rabbit이다.
- super는 [[HomeObject]] 객체를 통해 super를 찾기 때문에 animal 객체를 super로 인지한다.
- 이것이 this와 super의 다른 접근이라고 볼 수 있겠다.
let animal = { sayHi(){ console.log("animal"); } }; let rabbit = { __proto__: animal, sayHi(){ super.sayHi(); } }; let plant = { sayHi(){ console.log("plant"); } }; let tree = { __proto__: plant, sayHi(): rabbit.sayHi }; tree.sayHi(); // animal- [[HomeObject]] 메소드에서만 정의가 된다. 하지만 method()의 형태로 정의해야만 한다. method: function() 형태로 정의해서는 안된다.
- method: function(){…} 내부에서 super를 사용할 경우 SyntaxError가 발생한다.
화살표 함수
- 화살표 함수는 function을 __proto__를 가지긴 하지만, prototype property를 가지지 않는다.
let test = () => {}; console.log(test.prototype); // undefined