[JavaScript] 클래스(Class)

YJ·2023년 7월 16일
0

들어가기 전에

자바스크립트는 prototype 기반 언어라서 '클래스' 및 '상속'개념이 존재하지 않지만 prototype을 기반으로 클래스와 비슷하게 동작하게끔 하는 다양한 기법들이 도입돼 왔다.

ES6에서 클래스가 도입됐지만, 역시나 prototype을 기반으로 한 것이기 때문에 자바스크립트에서 클래스 상속을 구현했다는 것은 결국 prototype chaining을 잘 연결한 것으로 이해하면 된다.


클래스(Class)

  • 클래스(class) :: 어떤 사물의 공통 속성을 모아 정의한 추상적인 개념

  • 인스턴스(instance) :: 클래스의 속성을 지니는 구체적 사례

  • 프로토타입 메서드(prototype method) :: 클래스의 prototype 내부에 정의된 메서드 / 인스턴스가 마치 자신의 것처럼 직접 호출할 수 있음

  • 스태틱 메서드(static method) :: 클래스(생성자 함수)에 직접 정의한 메서드 / 인스턴스가 직접 접근할 수 없음 / 클래스(생성자 함수)를 this로 지정해 직접 접근해야만 호출 가능

단순하게 말하면 클래스는 'object를 뽑는 기계'다. 비슷한 object를 많이 만들 일이 있으면 클래스를 생성해 사용하면 된다.

function 기계 () {
   this.q = 'consume';
   this.w = 'snowball';
}

const nunu = new 기계();    // 기계 {q: 'consume', w: 'snowball'}

this새로 생성되는 object(인스턴스)를 가리킨다.
그러니까 this.q = 'consume' 은 새로 생성되는 object에 {q: 'consume'} 을 추가해달라는 의미인 것이다.

ES5 체계에서의 생성자 함수 및 프로토타입과 ES6의 클래스 비교

1. 문법

// ES5 생성자 함수
function 기계 (구멍) {
  this.q = 구멍;
  this.w = 'snowball';
}

const nunu = new 기계('consume');     // 기계 {q: 'consume', w: 'snowball'}
const garen = new 기계('strike');     // 기계 {q: 'strike', w: 'snowball'}


// ES6 클래스
class Hero {
  constructor (구멍) {
    this.q = 구멍;
    this.w = 'snowball';
  }
}

const nana = new Hero('hello');     // Hero {q: 'hello', w: 'snowball'}

2. 클래스 내에 정의한 메서드는 prototype에 저장된다.

// ES5 생성자 함수
function 기계 (구멍) {
  this.q = 구멍;
  this.w = 'snowball';
  this.showQ = function () {
    console.log(this.q);
  }
}

const nunu = new 기계('consume');    // 기계 {
                                    //   q: 'consume',
                                    //   w: 'snowball',
								    //   showQ: ƒ (), ➡️ ❗️객체 내부에 showQ 있음
					 			    //   __proto__: { constructor: ƒ 기계() }
					  			    // }

// ES6 클래스
class Hero {
  constructor (구멍) {
    this.q = 구멍;
    this.w = 'snowball';
  }
  showQ () {
    console.log(this.q);
  }
}

const nana = new Hero('hello');    // Hero {
                                   //   q: 'hello',
                                   //   w: 'snowball',
                                   //   __proto__: { constructor: ƒ Hero(), showQ: ƒ showQ() } ➡️ ❗️prototype 내부에 showQ 있음
                                   // }

☝🏼 여기서 생성자 함수가 클래스와 동일하게 동작하도록 만들고 싶으면 아래와 같이 수정하면 된다.

// ES5 생성자 함수
function 기계 (구멍) {
  this.q = 구멍;
  this.w = 'snowball';
}

기계.prototype.showQ = function() {
  console.log(this.q)
}

📌 그럼 생성자 함수로도 구현할 수 있는데 단순히 문법의 편의성을 위해 클래스가 탄생한 것일까?

아래의 코드는 인스턴스를 만들고자 했는데 실수로 new를 생략하고 작성한 경우를 나타낸 것이다.

const nunu = 기계('consume');    // undefined(기계 함수에 return문이 없으므로) ➡️ 문제가 없다.
const nana = Hero('hello');     // TypeError ➡️ 클래스는 new 없이 실행할 수 없다❗️

분명 개발자가 실수한 코드지만 생성자 함수의 경우 문제 없이 작동해 에러를 즉시 알아차릴 수 없다.
반면에 클래스를 사용하면 즉각적으로 에러를 잡아낼 수 있어 더 효율적으로 작업할 수 있다는 이점이 있다.

3. 상속

생성자 함수는 prototype을 이용해 상속(엄밀히 말하면 상속은 아니지만)을 구현했었다.
클래스에서의 상속(instance 생성 아니고, class로 class를 만드는 것!)은 extends 키워드를 사용한다.

// ES6 클래스
class Car {
  constructor(color) {
    this.color = color;
    this.wheels = 4;
  }
  stop() {    // myCar의 prototype의 prototype에 stop이 있다❗️
    console.log('STOP!');
  }
}

class Hyundai extends Car {
  park() {    // myCar의 prototype에 park가 있다❗️
    console.log('PARKING');
  }
}

const myCar = new Hyundai('blue');

4. 상위 클래스에 접근하는 방법

클래스에서는 super. 메서드로 부모 클래스에 정의된 메서드를 사용할 수 있다(자식 내부에 같은 이름의 메서드가 존재해도 오버라이딩(overriding) 되지 않고 부모껄 출력한다.).

// ES6 클래스
class Hyundai extends Car {
  park() {    
    console.log('PARKING');
  }
  stop() {
    super.stop();          // 'STOP!'
    console.log('OFF')     // 'OFF'
  }  
}

myCar.stop();

※ 참고 자료
코어 자바스크립트
객체지향 Class 문법 10분만에 이해시켜줌 (자바스크립트)
자바스크립트 중급 강좌 #15 클래스(Class)

profile
Hello

0개의 댓글