Prototype - 3. JavaScript에서의 Class

Jeong-ho·2022년 4월 28일
0

JavaScript

목록 보기
3/3
post-thumbnail
  1. Prototype 디자인 이론
  • 비트겐슈타인 : 용도의미론, 가족유사성
  • 로쉬 : 프로토타입 이론(원형의미론)
  • prototype 이론으로 javascript 이해하기
    • prototype으로 객체 지향 프로그래밍 해보기
    • 호이스팅
    • this
  1. JavaScript에서의 Prototype
  • 표준 내장 객체
  • [[Prototype]] 그리고 __proto__
  1. JavaScript에서의 Class
  • class의 구성
    • 필드 선언
    • constructor
    • 정적 속성
    • 메소드
  • class에서 상속
  • class 상속을 prototype으로 구현해보기

JavaScript에서의 Class

 Prototype 시리즈의 마지막인 이번 파트에서는 자바스크립트 내에 클래스에 대해 살펴볼 것이다. 클래스의 구성과 상속 그리고 프로토타입으로 구현하는 클래스의 상속 순으로 진행하겠다.

class의 구성

 클래스 구성이 어떻게 되어있는지 간략하게 살펴보자.

  • 필드 선언
  • constructor
  • 정적 속성(이 글에서는 속성을 편의상 변수, 메소드 전부 칭하는 걸로 한다)
  • 메소드
class 나클래스 {
  // 필드 선언
  나변수1 = 1;
  #나변수2 = 2;
  
  // constructor
  constructor(매개변수1, 매개변수2) {
    this.나변수3 = 매개변수1;
    this.나변수4 = 매개변수2;
  }
  
  // 정적 메소드
  static 나정적(인스) {
    return 인스.나변수1 + 인스.나변수4;
  }
  
  // 메소드
  나메소드() {
    return this.#나변수2 + this.나변수4;
  }
}

const 나인스 = new 나클래스(3, 4);

console.log(나인스) // 나클래스 {나변수1: 1, 나변수3: 3, 나변수4: 4, #나변수2: 2}

console.log(나인스.나메소드) // 6

console.log(나클래스.나정적(나인스)) // 5

필드 선언

 mdn 문서에 따르면 필드 선언은 표준은 아니고 실험으로서 제안된 기능이다. 공공(public) 필드 선언과 개인(private) 필드 선언으로 나뉜다.

 필드 선언은 매개변수로 변하는 속성과 고정적인 속성을 분리하여 코드 가독성을 높일 수 있다. 개인 필드 선언의 경우, 인스턴스 내 속성으로서 존재는 하지만, 클래스 내부의 로직으로서만 읽고 쓰기가 가능하다.

class 나클래스 {
  #나개인 = "나개인"
  
  constructor(매개변수) {
    this.나변수 = 매개변수
  }
}

const 나인스 = new 나클래스("나변수");

console.log(나인스) // 나클래스 { 나변수: "나변수", #나개인: "나개인" };
console.log(나인스.#나개인) // SyntaxError;

 메소드를 필드 선언해 버리면, 인스턴스가 생성될 때마다 새로운 메소드가 같이 생성되기 때문에, 유의할 필요가 있다.

constructor

 constructor의 경우 프로토타입에서의 생성자 함수와 같은 역할을 한다. 즉, 인스턴스 객체를 생성하고 초기화하는 역할을 한다.

 constructor에서도 역시나 메소드를 정의할 수 있지만, 인스턴스 객체가 생성될 때마다, 해당 메소드 또한 같이 생성되기에 비효율적이라 할 수 있다.

 클래스에 constructor를 따로 정의하지 않으면 자동으로 constructor() {} 빈 생성자를 사용한다.

정적 속성

 정적 속성은 static 키워드를 붙여 선언한다. 이는 객체를 통해 불러오는 것이 아닌, 클래스 그 자체에서 호출한다.

 정적 속성은 내용 자체는 단순한데, 어떤 경우에 사용해야 효율을 볼 수 있는지에 대해 고민해야 한다.

 mdn에 따르면 정적 메소드의 경우, 관련 객체 생성 및 복사 등 유틸리티 함수를 정의하는 데 용이하고 정적 변수의 경우, 캐시나 고정된 구성 및 설정을 정의하는데 용이하다고 한다.

메소드

 메소드는 클래스 내부에서 작성하면, prototype 속성에 자동으로 정의된다. 이는 prototype을 통한 객체지향 프로그래밍에서 권장한 방법과 유사하다.

 변수는 각각의 인스턴스에 포함하고, 메소드는 계속해서 생성하는 것이 아닌 프로토타입에 정의하여 공유하는 방식을 취하는 것이다.

 화살표 함수로 작성할 경우, 함수 표현식으로 처리되고 이는 필드 선언을 한 것과 같이 인식되어, 인스턴스에 포함된 채 실린다. 유의해야 한다.

class에서 상속

 class는 extends키워드를 통해 자식 클래스로 쉽게 상속을 할 수 있다. 상속이라고 표현했지만, extend의 단어 뜻 그대로 '클래스의 확장'이라는 느낌으로 받아들여도 좋다.

class 드링크 {
  constructor(매개변수1) {
    this.이름 = 매개변수1;
  }
  
  마신다() {
    console.log(`${this.이름}을 마신다!`);
  }
}

class 에너지드링크 extends 드링크 {
  constructor(매개변수1, 매개변수2) {
    // 만약 자식 클래스에서 this를 super()전에 작성하면,
    // 참조오류가 발생한다.
    super(매개변수1);
    
    this.본사위치 = 매개변수2;
  }
  
  마신다() {
    // 기존 메소드에서 추가하기 위해, super 키워드를 사용
    super.마신다();
    console.log("힘이 콸콸콸!");
  }
}

const 레드불 = new 에너지드링크("레드불", "오스트리아");

console.log(레드불); // 에너지드링크 { 이름: "레드불", 본사위치: "오스트리아" }

console.log(레드불.마신다()); // "레드불을 마신다!" "힘이 콸콸콸!"

super키워드는 부모 클래스의 함수를 호출할 때 사용된다. super()는 생성자 함수를 호출하고 super.prop는 부모 클래스의 메소드를 호출한다. 해당 키워드는 정적 속성에서도 물론 사용할 수 있다.

class 상속을 prototype으로 구현해보기

 위의 드링크, 에너지드링크 클래스 코드를 프로토타입으로 구현하면 다음과 같다.

function 드링크(매개변수1) {
  this.이름 = 매개변수1;
}

// 효율성을 위해 변수와 메소드를 분리해서 기입한다.
드링크.prototype.마신다 = function() {
  console.log(`${this.이름}을 마신다!`);
}

function 에너지드링크(매개변수1, 매개변수2) {
  // this가 드링크 클래스에 묶여 있다.
  // 즉, 드링크에 new 키워드를 넣었을 때만, 드링크 클래스의 this.이름이 의미가 생긴다.
  // 그러나 우리는 에너지드링크 클래스에 드링크 클래스의 변수를 상속받아야 한다.
  // 이를 해결하기 위해서는 .call()을 통해 this를 에너지드링크 클래스에 바인딩하면 된다.
  드링크.call(this, 매개변수1);
  this.본사위치 = 매개변수2;
}

// Object.create(proto)는 proto를 프로토타입 속성으로 갖는 새 객체를 만든다.
// 즉, Object.create(proto)를 통해 만들어진 객체는 [[Prototype]]을 통해 proto에 있는 속성을 사용할 수 있다.
에너지드링크.prototype = Object.create(드링크.prototype);

// object.create()를 통해 prototype 속성을 만들면, constructor가 없다. 생성자 함수를 지정해준다.
에너지드링크.prototype.constructor = 에너지드링크;

에너지드링크.prototype.마신다 = function() {
  드링크.prototype.마신다.call(this);
  console.log("힘이 콸콸콸!");
}

const 레드불 = new 에너지드링크("레드불", "오스트리아");

console.log(레드불); // 에너지드링크 { 이름: "레드불", 본사위치: "오스트리아" }

console.log(레드불.마신다()); // "레드불을 마신다!" "힘이 콸콸콸!"

나가는 말

 내용을 간략하게 정리하면 다음과 같다.

  • class는 필드 선언, constructor, 정적 속성, 메소드로 구성되어 있다.
  • class의 상속은 extends키워드로 구현하고 super키워드로 부모 클래스의 함수 호출이 가능하다.

 지금까지 프로토타입과 관련하여 이론적인 부분부터 자바스크립트에서의 구현, class까지 살펴보았다. 전반적인 아쉬운 점을 들자면 다음과 같다.

  • 표면적인 부분만 거론했지, 어떻게 작동되고 메모리상 어떻게 할당되는 지 등, 깊은 설명이 전무하다.
  • 정확한 활용 방법에 대한 설명이 부족하다.

 면접 질문과 관련하여 외웠던 부분들을 이해해보자는 취지에서 글을 시작했다. this, 호이스팅, class 문법 등이 이에 해당했는데, 결국 끝에는 프로토타입이 나와 프로토타입을 주제로 시리즈를 작성하였다. 내용은 별거 없지만, 여러 글을 살펴보면서 필자 나름대로 자바스크립트에 대해 살짝 통성명 정도는 한 것 같은 기분이 들어 좋았다.

참고한 사이트

사이트1
사이트2
사이트3

0개의 댓글