클래스 상속

Vorhandenheit ·2021년 9월 7일
0

JS.코어

목록 보기
19/29
post-custom-banner

클래스 상속

1.'extends' 키워드

class Animal {
	constructor(name) {
    	this.speed = 0;
      	this.name = name;
    }
  run (speed) {
  	this.speed = speed;
  }
  stop () {
  	this.speed = 0
  }
}
let animal = new Animal('동물');

  • 상속
clas Rabbit extends Animal {
	hide() {
    }
}

let rabbit = new Rabbit()

클래스 Rabbit을 이용해 만든 객체는 Animal에 정의된 메서드에도 접근할 수 있습니다.

키워드 extedns는 Rabbit.prototype.[[prototype]]을 Animal.prototype으로 설정

2. 메서드 오버라이딩

class Rabbit은 class Animal에 있는 메서드를 그대로 상속받습니다.

class Rabbit extends Animal {
	stop() {
    }
} //둘다 같은 메서드가 있을 경우, 가까이 있는 메서드를 사용

부모 메서드 전체를 교체하지않고 , 부모 메서드 일부만 변경하고 싶을 때나 확장하고 싶을 때에는 super를 사용

  • super.method(...)는 부모 클래스에 정의된 메서드, method를 호출
  • super(...)는 부모 생성자를 호출, 자식 생성자 내부에서만 사용 할 수 있음
class Animal {
	
  constructor(name) {
  	this.speed = 0;
    this.name = name;
  }
  
  run() {
  	this.speed =speed;
  }
  
  stop() {
  	this.speed = 0
  }
}


class Rabbit extend Animal {
	hide() {
    }
  	stop() {
    	super.stop(); // 부모클래스의 stop을 호출해 멈춤
      this.hide()
    }
}
let rabbit = new Rabbit()

3. 생성자 오버라이딩

클래스가 다른 클래스를 상속받고 constructor가 없는 경우에는 아래처럼 비어있는 constructor가 만들어짐

class Rabbit extends Animal {
	constructor(...args) {
    	super(...args);
    }
}

constructor가 없으면 상속받은 Rabbit은 자동적으로 constructor와 인수를 모두 전달 받음

class Animal {
	constructor(name) {
    	this.speed = 0;
      	this.name= name;
    }
}


class Rabbit extends Animal {
	constructor(name, earLength) {
    	this.speed = 0;
      	this.name = name;
      	this.earLength = earLength
    }
} // 상속받는 객체가 super가 없기 떄문에 에러발생

왜 에러가 발생할까?

자바스크립트는 '상속 클래스의 생성자 함수'와 그렇지 않은 생성자 함수를 구분함
상속 클래스 생성자 함수에는 특수 내부 프로퍼티인 [[ConstructorKind]]: "derived" 가있음

일반 클래스가 new와 함께 실행되면, 빈 객체가 만들어지고 this에 이 객체가 할당되지만 상속 클래스의 생성자 함수가 실행되면, 상속 클래스의 생성자 함수는 빈 객체를 만들고 this에 할당하는 일을 부모 클래스 생성자가 처리해주길 기대함

그래서 this에 객체가 들어오지않기 떄문에 에러가 발생

클래스 필드 오버라이딩

class Animal {
	name = 'animal'
	
	constructor() {
      alert(this.name)
    }
}

class Rabbit extends Animal {
	name = 'rabbit' // 오버라이딩
}

new Animal(); // animal
new Rabbit(); // animal

부모생성자는 자식 클래스에서 오버라이딩한 값이 아닌, 부모 클래스 안의 필드 값을 사용한다

  • 메서드 사용시
class Animal {
	showName() {
    	alert('animal')
    }
  constructor() {
  	this.showName();
  }
}

class Rabbit extends Animal {
	showName() { //오버라이딩
   		alert('rabbit') 
    }
}

new Animal(); // animal
new Rabbit(); // rabbit

위에 것과 차이 발생, 이유는 필드 초기화 순서 때문

  • 아무것도 상속받지 않는 베이스 클래스는 생성자 실행 이전에 초기화
  • 부모 클래스가 있는 경우에는 super()실행 직후에 초기화

new Rabbit을 실행하면 super()가 호출되고 부모 생성자가 실행, 하위 클래스 필드 초기화 순서에 따라 하위 클래스 Rabbit의 필드는 super()실행 이후에 초기화됨

super 키워드와 [[HomeObject]]

1) 내부에서 super가 어떻게 동작할까?

let animal = {
	name : "동물",
  	eat() {
    	alert(`${this.name} 이/가 먹이를 먹습니다.`)
    }
};

let rabbit = {
	__proto__ : animal,
  	name: "토끼",
  	eat() {
    	this.__proto__.eat.call(this);
    } // eat의 프로토타입 (animal)을 가져오고 현재 객체 컨택스트 기반하여 eat을 호출
}
rabbit.eat() // 토끼 이/가 먹이를 먹습니다.
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(); // RangeError:

모든 객체 메서드는 프로토타입등이 아닌 현재 객체 this로 가짐, 그래서 this.__proto__에는 같은 값, rabbit이 할당됨
체인위로 올라가지않고 모두 rabbit.eat을 호출하기 때문에 무한 루프에 빠짐

[[HomeObject]]

이런 문제를 해결하기 위해 함수 전용 특수 내부 프로퍼티 [[HomeObject]] 사용
클래스 이거나 객체 메서드인 함수의 [[HomeObject]]프로퍼티는 해당 객체가 저장
super는 [[HomeObject]]를 이용해 부모 프로토타입과 메서드를 찾음
[[HomeObject]]는 오직 super 내부에서만 유효

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();
  }
};
profile
읽고 기록하고 고민하고 사용하고 개발하자!
post-custom-banner

0개의 댓글