본문 바로가기
Programming Languages/Javascript

ES6 Classes and Super...?

by Calvin H. 2022. 5. 31.

선결론 : Sugar Coating 되어 버린 ES6 클래스 문법을 이용하면 편리하다

 

 

자바스크립트는 사실 클래스의 뚜렷한 기반이 있는 언어가 아니다. 처음부터 지금까지 자바스크립트는 OOP가 아닌 객체 지향 언어일 뿐이다. 그렇기에 꽤 오랜 시간동안 클래스를 활용하기 위한 몸부림치는 노력들이 있었으며 그 노력들은 일종의 임시 방편이나 일시적인 해결책에 지나지 않았다. 결국에는 ES6라는 문법에 Class 와 상속이 가능한 Super 가 등장하게 되면서 그 이후로 언어를 접하는 사람들은 자바스크립트가 객체 지향 프로그래밍 이라는 착각을 할 수도 있다. 허나, class 나 super 등의 문법은 사실 기존에 사용했던 상속 및 클래스 생성 방법들을 깔끔하게 정리해준 것 뿐 그 이하도 이상도 아니다.

 

자 그럼, 지나친 소개는 그만하고 이제 본론으로 들어가보장

 

일단 클래스 사용법은 아래와 같다

 

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

 

위에 보이는 예시는 MDN 문서에서 제시된 예시이다. 

보면 알겠지만 class라고 선언 후 클래스의 이름은 (대문자로 시작) 다음으로 오며, 바로 중괄호가 시작된다. 

즉, 인자 값들을 넣는 소괄호 같은 건 안 보인다.

 

다음 줄에 바로 보이는 것은 constructor 함수인데, 자바스크립트를 이미 다루고 있는 사람들이라면, 함수가 만들어질 때는 함수라는 객체와 생성자 함수 두 개가 동시에 만들어진다는 것을 알고 있을 거다. 

 

말 그대로 생성자 함수에는 인자들을 받는데 그 내부에는 this 로 클래스의 속성에 추가해주는 기능이 있다.

 

이렇게 클래스를 만들 수 있도록 해준 ES6문법에 일단 감사의 박수를 치고 다음으로 넘어가장

 

Class, No Hoisting

 

자 Hoisting 에 대해서 얼마나 알고 있을지 모르겠지만 간단하게 설명만 하자면, hoisting 이란 것은 자바스크립트가 실행이 될 때 변수들과 함수들을 먼저 선언하도록 하는 메모리 단계와 실제로 값들을 할당하고 프로그램을 돌리는 실행 단계가 있다. 클래스를 사용하면 함수나 변수와는 달리 hoisting 이 되지 않으므로 먼저 선언 후 사용해야 된다는 주의점이 있다.

 

그렇기에 만약에 실수로 클래스 선언 전에 사용을 하게 된다면 Reference Error 가 뜬다... 중요하지는 않지만 알고 있으면 편리하다.

 

One Constructor Function

생성자 함수는 클래스를 생성할 때 사용되는 매우 핵심 역할을 지닌다. 그래서 그런지는 모르겠지만 하나의 클래스에 여러 개의 생성자 함수를 넣을 수는 없다

 


Inheriting With Extends and Super

자 그럼 이제는 상속하는 방법에 대해서 살펴보자.

이번에도 MDN의 깔끔하게 정리된 문서에 포함된 코드 예시를 아래에 첨부했다.

 

class Animal { 
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

class Dog extends Animal {
  constructor(name) {
    super(name); // call the super class constructor and pass in the name parameter
  }

  speak() {
    console.log(`${this.name} barks.`);
  }
}

let d = new Dog('Mitzie');
d.speak(); // Mitzie barks.

 

보면 일단 Animal이라는 클래스를 이전에 설명했던 것처럼 작성을 하고 생성자 함수 또한 한 개에 속성 또한 this.name을 준다.

여기에서는 추가적으로 클래스에 메소드를 더하는데 speak라는 메소드는 현재 this.name 을 출력하게 되어있다.

 

다음으로 나오는 클래스는 Dog 인데, 약간 다른 점이 보인다. 그것은 즉 extends 를 사용한다는 것이다. 상속을 하겠다라고 말할 때 사용되는 extends는 이미 만들어진 클래스를 상속할 수 있는 기능이 있다. 이번에 보면 Dog라는 클래스는 Animal 클래스로부터 상속을 받는다.

 

자세히 보면 생성자 함수에 Animal 과 똑같이 name이라는 인자를 받는데, 이번에는 선언을 하지 않고 super() 안에다가 추가만 해준다. 

Super라는 것은 상속하는 부모 객체를 가리킨다고 보면 조금 더 이해가 쉬울텐데, 부모에게서 생성자 함수의 같은 기능을 상속하는 것이다. 

여기서 중요한 것은 super에 추가하는 것들은 부모 객체에서 생성자 함수가 받는 인자 순대로 실행이 된다는 것이다. 

 

또한 굳이 ES6문법이 아니더라도 일반적인 Function-Based Class 를 상속할 수 있다는 장점이 있다 (어디에 활용 가능하지?)

 

Methods & Super

만약에 부모의 메소드를 상속받고 싶긴한데 추가적인 기능들을 더 수행하고 싶다???

그렇다면 아래와 같이 코드를 작성하면 추가적인 기능들을 할 수가 있다.

 

class Cat { 
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

class Lion extends Cat {
  speak() {
    super.speak();
    console.log(`${this.name} roars.`);
  }
}

let l = new Lion('Fuzzy');
l.speak(); 
// Fuzzy makes a noise.
// Fuzzy roars.

 

위의 예시를 자세히 보면 Lion 이라는 클래스는 Cat 클래스에서부터 상속을 받고 따로 생성자 함수를 만들지 않았다. 또한 Speak라는 메소드에 super.speak()를 추가했는데, 이 기능은 부모의 speak 메소드를 가지고 오며 부모의 speak함수를 실행한다 (가로가 있당). 또한 부모의 메소드와 이름이 동일하기 때문에 일종의 override 이기도 하다. 즉, 같은 이름의 함수 메소드가 있지만 부모의 함수 메소드 또한 실행시키고 싶을 때 매우 유용한 방식이므로 중요하다.

 

 


호환성???

아래에 정확한 호환성 표가 첨부된 MDN 공식 문서를 남기겠지만, 인터넷 익스플로러에서는 이 글의 내용들을 하나도 실행 못한다는 슬프고도 슬프 사실이 있다... 그러니 functional 함수들에 대해서도 알고 있는 게 아마 좋을거다...

 

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes

 

Classes

JavaScript classes, introduced in ECMAScript 2015, are primarily syntactical sugar over JavaScript's existing prototype-based inheritance. The class syntax does not introduce a new object-oriented inheritance model to JavaScript.

developer.mozilla.org