Front-end/JavaScript

JS OOP 4편 - extends(JS 클래스 상속)

파리외 개발자 2023. 2. 13. 01:50
JS의 OOP에서는 
extends를 통해 상속을 구현하고
부모클래스의 구성요소를 자식요소가 가져다 쓸 수 있도록
한다.

 

상속이 필요한 경우

class Elf {
  constructor(name, weapon) {
    this.name = name;
    this.weapon = weapon;
  }
  attack() {
    return "attack with" + this.weapon;
  }
}

const fiona = new Elf("Fiona", "ninja stars");
const ogre = { ...fiona };

console.log(ogre);
ogre.__proto__; //empty obj
console.log(fiona === ogre); //false
ogre.attack(); //not func err

Elf클래스의 인스턴스인 fiona가 있다.

해당 인스턴스 객체의 구성요소를 ogre에 할당한다면

ogre는 Elf클래스의 인스턴스가 될 수 있을까?

우선 인스턴스 fiona의 내용물은 ogre에 그대로 복사되었다.

객체의 프로토타입 속성을 보면

ogre는 기본 객체를 상속받고

fiona는 Elf클래스를 상속받는다.

즉, ogre는 빈 객체를 상속받는다.

그렇기 때문에 내용물은 같더라도 두 객체는 다른 객체다.

결과적으로 ogre는 인스턴스 객체인 fiona와 내용물은 같더라도

인스턴스 객체가 상속받는 클래스 Elf와의 연결이 없기 때문에

Elf의 attack메서드를 사용하지 못한다.

여기서 ogre와 fiona를 공통적인 부분(예를 들어 attack)은 가져가면서

또 차이점(오우거와 엘프의 차이)은 다르게 지정하고 싶을 때 상속을 사용할 수 있다.

 

Extends의 생성자

//extends
class Character {
  constructor(name, weapon) {
    this.name = name;
    this.weapon = weapon;
  }
  attack() {
    return "attack with" + this.weapon;
  }
}

공통부분을 캐릭터 클래스로 지정하고

이름과 무기, 공격행동을 공통 속성으로 해당 클래스에 정의할 수 있다.

class Elf extends Character {
  constructor(name, weapon, type) {
    console.log(this); //err
    super(name, weapon); //Character's constructor
    console.log(this); //super후에 인스턴스가 생성되고 this에 접근가능
    this.type = type;
  }
}

const doby = new Elf("Doby", "cloth", "house");

그리고 정의하고 싶은 Elf클래스를 만들고 Character클래스를 상속시킨다.

여기서 상속받은 클래스의 생성자에는 super를 통해 부모 클래스의 생성자 속성들을 참조할 수 있다.

상속을 받는 클래스는 생성자함수에 super를 사용해야지만 

인스턴스가 생성되면서 this가 인스턴스를 가리키게 된다.

여기서 super의 인자는 부모 클래스의 생성자 함수의 인자로 전달된다.

super가 동작한 후에야 this는 클래스 Elf를 가리키게 된다.

여기서 속성 type: 'house'가 없는 이유는 아직 할당되기 전이기 때문이다.

인스턴스 객체 doby는 부모클래스의 속성인 이름, 무기와

Elf클래스만의 속성인 type을 가지고 공통 메서드인 attack에 접근이 가능하다.

class Ogre extends Character {
  constructor(name, weapon, color) {
    super(name, weapon);
    this.color = color;
  }
  makeFort() {
    return "strongest fort in the world made";
  }
}

const shrek = new Ogre("Shrek", "club", "green");
shrek.makeFort();
shrek.attack();

이번엔 Elf와 공통부분인 Character클래스를 가지지만

차이점을 가지는 ogre클래스를 생성한다.

해당 인스턴스는 Ogre만의 메서드를 사용할 수 있으면서

공통 메서드 또한 사용할 수 있다.

클래스 상속의 프로토타입 체인

console.log(Ogre.isPrototypeOf(shrek)); //false
console.log(Ogre.prototype.isPrototypeOf(shrek)); //true
console.log(Character.prototype.isPrototypeOf(Ogre)); //false
console.log(Character.prototype.isPrototypeOf(Ogre.prototype)); //false

console.log(doby instanceof Elf); //true
console.log(doby instanceof Character); //true
console.log(shrek instanceof Elf); //false
console.log(shrek instanceof Character); //true

인스턴스 객체인 shrek은 Ogre클래스의 상속을 받는 것이 아니다.

인스턴스는 클래스의 프로토타입 객체의 상속을 받는다.

오거 클래스 자체가 캐릭터 클래스의 프로토타입 객체를 상속받는 것이 아니다.

자식 클래스의 프로토타입 객체가 부모 클래스의 프로토타입 객체를 상속받는다.

자식 클래스의 인스턴스는 부모 클래스의 인스턴스이기도 하다.

부모 클래스를 동일하게 가지더라도 

다른 자식 클래스의 인스턴스들은 서로 인스턴스를 공유하지 않는다.