class Rabbit extends Animal {
constructor(){
super();
}
}
super의 주체는 무엇인가?
나의 super의미가 내포되어있어 하위클래스 생성객체가 된다.
let animal = {
name: "동물",
eat() {
console.log(`${this.name} 이/가 먹이를 먹습니다.`);
}
};
let rabbit = {
__proto__: animal,
name: "토끼",
eat() {
this.__proto__.eat.call(this);
super.eat();
}
};
rabbit.eat();
rabbit에서 상위객체의 this가있는 메소드를 호출하려면 this를 바인딩해야 한다.
this.__proto__.eat.call(this);
상위객체로 접근하면 위와같이 반드시 this를 원하는 객체로 바인딩해야 한다.
super.eat();
자신객체로부터 상위객체메소드를 연결한후 호출하는 방식으로 this를 바인딩하지 않아도 된다.
모든 객체메서드는 [[HomeObject]]숨김속성을 가지며 해당 객체가 참조할당된다.
super는 [[HomeObject]]를 이용해 상위객체를 참조한다.
let animal = {
name: "동물",
eat() {
alert(`${this.name} 이/가 먹이를 먹습니다.`);
}
};
let rabbit = {
__proto__: animal,
eat() {
// call을 사용해 컨텍스트를 옮겨가며 부모(animal) 메서드를 호출합니다.
this.__proto__.eat.call(this); // (*)
}
};
let longEar = {
__proto__: rabbit,
eat() {
// longEar를 가지고 무언가를 하면서 부모(rabbit) 메서드를 호출합니다.
this.__proto__.eat.call(this); // (**)
}
};
longEar.eat();
위와같이 this.__proto을 사용해서 상위객체 메소드를 찾아가면 무한루프에빠진다. 원인은 this바인딩될때 this.proto__의 this도 바인딩되기 때문이다.
let animal = {
name: "동물",
eat() { // animal.eat.[[HomeObject]] == animal
alert(`${this.name} 이/가 먹이를 먹습니다.`);
}
};
let rabbit = {
__proto__: animal,
name: "토끼",
eat() { // rabbit.eat.[[HomeObject]] == rabbit
super.eat();
}
};
let longEar = {
__proto__: rabbit,
name: "귀가 긴 토끼",
eat() { // longEar.eat.[[HomeObject]] == longEar
super.eat();
}
};
// 이제 제대로 동작합니다
longEar.eat();
super를 사용하면 정확한 상위객체를 찾는다.
[[HomeObject]]의 부작용
[[HomeObject]]는 객체메소드의 숨김속성으로 자신객체를 참조할당한다고 했다.
한번 설정된 [[HomeObject]]는 변경이 불가하며 [[HomeObject]]속성은 super에의해서만 사용된다.
객체메소드가 다른 객체의 메소드로 할당되고 super가 호출되면 [[HomeObject]]에 이전 객체정보가 저장되어있어 super는 제대로 평가되지 않는다.
let animal = {
eat() {
console.log(1);
}
};
let rabbit = {
__proto__: animal,
eat: function() {
super.eat();
}
};
rabbit.eat();
객체메소드를 정의할때 표현식기법으로 정의하면 함수가 호출될때 메소드가 생성되기때문에 [[HomeObject]]속성이 설정되지 않는다.
반드시
let rabbit = {
__proto__: animal,
eat() {
super.eat();
}
};
함수정의방식으로 정의해야 한다.