책정리/Deep Dive Javascript

자바스크립트 클래스 사용 방식 및 특징

뽀글보리 2023. 11. 30. 07:43
반응형

이전 글에서 살펴보았듯이, 자바스크립트는 프로토타입을 사용하여 객체 지향 프로그래밍을 할 수 있다. ES6에서 도입된 클래스는 자바나 C 언어의 클래스 문법과 유사하게 객체 생성할 수 있도록 한다. 자바스크립트의 클래스는 실제로는 함수처럼 동작하며, 기존의 프로토타입 생성 방식과 다르지 않다. 따라서 클래스를 문법적 양념(syntactic sugar)일 뿐이라고 말하기도 한다.

클래스가 도입된 이유

function Student(name,age){
  this.name = name
  this.age = age
}
const student1 = new Student('king',20) // {'name': 'king', 'age': 20}
const student2 = Student('king', 20); // undefined

 

위 Student는 일반 함수이고, new 키워드를 붙여 호출하면 this를 반환하는 생성자 함수로 동작한다. 이 때 주의할 점은 new를 붙여 호출하지 않으면, 일반함수처럼 동작한다는 것이다. 자바스크립트는 함수를 일반 함수 또는 생성자 함수처럼 호출하는 두 가지 방식을 모두 허용하며, 이는 혼란을 초래할 수 있다. 이에 반해 클래스에서는 new 연산자 없이 호출하면 에러가 발생한다. 따라서 원하는 생성자의 의도로만 Student 인스턴스를 생성할 수 있다는 장점이 있다.

클래스를 정의하는 방법

class Student{
  constructor(name,age){
    this.name = name
    this.age = age
  }

 getAge(){
   return this.age;
 }

 static hello(){
   console.log("hello")
 }
}


const student1 = new Student('king',20)
console.log(student1.getAge()) // 20
console.log(Student.hello())
  • constructor를 정의하여 인스턴스를 생성하면서 프로퍼티 값을 초기화할 수 있다.
  • class 내부에서 프로토타입 메서드를 정의할 수 있다.
  • static 키워드를 사용해서 정적 메서드를 정의할 수 있고, 정적 메서드는 클래스에 직접 접근하여 사용할 수 있다.
  • console.log(typeof Student)를 한다면 function이 출력된다. 클래스는 자바스크립트에서 생성자 함수이기 때문이다.

이를 함수 및 프로토타입 기반으로 작성하면 다음과 같다.

var Student = (function() {
  function Student(name, age){
    this.name = name;
    this.age = age;
  }

  Student.prototype.getAge = function() {
      return this.age;
  }

  Student.hello() = function() {
    console.log("hello");
  }

  return Student;
}();

 

private 필드

class Student {
  #name= '';

  constructor(name) {
    this.#name = name;
  }
}

const student1 = new Student('me');
console.log(me.#name); // SyntaxError

 

#을 사용하여 private 필드를 정의할 수 있다. 클래스에서 필드를 정의하면 기본적으로 공개(public)이기 때문에 외부에서 바로 접근할 수 있다. private 필드는 클래스 내부에서만 참조할 수 있고, 인스턴스나 자식 클래스에서는 접근할 수 없다.

 

상속

 

상속이란, 기존 클래스를 상속받아 새로운 클래스를 확장하여 정의하는 것을 말한다. 상속을 사용하면 클래스의 속성 일부 또는 전체를 재사용할 수 있다는 점에서 유연하다.

class DateFormatter extends Date {
  getFormattedDate() {
    return `${this.getDate()}-${this.getMonth()+1}-${this.getFullYear()}`; // 1
  }
}

const date1 = new DateFormatter('August 19, 1975 23:15:30'); // 2

console.log(date1.getFullYear()) // 3
console.log(date1.getFormattedDate()); // 4
// Expected output: "19-Aug-1975"

 

다음 DateFormatter이라는 클래스는 Date라는 클래스를 상속해서 만든 클래스이다. 다음을 확인할 수 있다.

  1. Date 클래스를 상속한 DateFormatter는 상위 클래스의 메서드를 활용할 수 있다.
  2. new 키워드를 사용하여 인스턴스를 생성하면 상위 클래스의 생성자가 호출된다.
  3. 인스턴스에서 getFullYear()를 접근하면 프로토타입 체인에 의해서 먼저 DateFormatter 메서드가 있는 지 확인하고, 존재하지 않을 경우에는 상위 프로토타입인 Date에서 getFullYear메서드가 있는 지 확인한다. 존재하므로, 해당 메서드를 실행한다. 따라서 인스턴스는 상위 클래스의 메서드를 활용할 수 있다.
  4. Date의 getFormattedDate 메서드가 오버라이드 되었다.

클래스와 함수에서 다른 점

  1. 클래스는 new 연산자 없이 호출하면 에러가 발생한다.
  2. extends와 super 키워드를 제공한다.
  3. 클래스는 호이스팅이 발생하지 않는 것처럼 동작한다. (모든 변수, 함수, 클래스 선언은 호이스팅 발생하는 것이 맞다. 그러나 let, const와 유사하게 class 선언시점까지는 일시적 사각지대에 빠져 접근할 수 없다.)
  4. 클래스 내의 모든 코드는 암묵적으로 strict mode가 지정되어 실행되며 strict mode를 해제할 수 없다.

참고

반응형