자바스크립트의 클래스와 객체지향

0

Javascript

목록 보기
12/13
post-thumbnail

자바스크립트에서 클래스는 객체지향을 익숙한 키워드로 구현하기 위해 만들어진 문법적 설탕 역할을 한다고 볼 수 있습니다. 하지만 클래스를 사용한다면 기존 생성자 함수 사용법과 다른 점들이 있습니다. 따라서 자바스크립트의 클래스는 ES6에서 도입된 새로운 객체 생성 매커니즘이라고 할 수 있겠습니다. 이번 포스트에서는 자바스크립트의 클래스와 이를 이용하여 올바른 객체지향 프로그래밍을 하는 원칙에 대해 알아보기로 합니다.

이 포스트는 코드스피츠의 "객체지향 자바스크립트" 강의를 기반으로 작성되었습니다.
https://www.youtube.com/watch?v=E9NZ0YEZrYU&t=1618

클래스 vs 생성자함수

class 키워드를 사용하여 객체를 생성할때는 생성자함수로 객체를 생성할 때와 다음과 같은 대표적인 차이점이 있습니다.

class생성자 함수
new 연산자 없이 호출하면 에러new 연산자 없이도 호출 가능(undefined 반환)
extends, super키워드 지원지원 안함
함수 객체이지만 let, const로 선언한 변수처럼 호이스팅(TDZ)선언문: 함수 호이스팅 발생
표현식:변수 호이스팅 발생
암묵적으로 strict mode적용strict mode가 적용되지 않음
constructor, 프로토타입 메서드, 정적 메서드 모두 [[Enumerable]]값이 false-

class 키워드의 사용

class Person {
  constructor(name){
    this.name = name;
  }
  
  sayHi(){
	console.log('Hi!');
  }
  
  static sayHello(){
    console.log('Hello!');
  }
}

선언

class 키워드를 통해 선언합니다. 익명, 기명 표현식 또한 가능합니다.

class Person { ... } // 클래스 선언문
const Person = class { ... } // 익명 표현식
const Person = class MyPerson { ... } // 기명 표현식

인스턴스 생성

클래스는 결국 생성자 함수입니다. 다만 class 키워드를 사용하면 더욱 명료하고 견고한 조건들이 적용되는 생성자 함수를 만들었다고 생각하면 될 것 같습니다. 예를 들어 class 키워드로 만든 생성자 함수는 반드시 new 키워드를 통해 호출되어야 합니다. 아니면 에러가 발생합니다.

class Person { ... }
const me = new Person('Kenny'); // new 키워드 사용 필수!

메서드 선언

클래스 몸체에는 constructor, 프로토타입 메서드, 정적 메서드 이렇게 3가지 종류의 메서드를 정의할 수 있습니다.

constructor

인스턴스를 초기화하고 생성할 수 있는 특수한 기능의 메서드입니다. prototype객체의 constructor 프로퍼티와 이름이 같아 헷갈릴 수 있지만, 직접적인 관련이 없는 전혀 다른 개념입니다.

class Person {
  constructor(name) {
    // 인스턴스 생성 및 초기화
    this.name = name;
  }
}

여기서 생성자 함수와 큰 차이가 느껴집니다. 생성자 함수에는 constructor라는 예약된 메서드가 없습니다. 생각해보니 생성자 함수 자체가 하는 역할을 클래스의 constructor 메서드가 하고 있는것 같습니다. 맞습니다. 클래스의 constructor 메서드는 사실 메서드로 해석되는 것이 아닌, 클래스 코드 평가시점에 생성되는 함수 객체의 코드 일부가 됩니다. 다시 말해, 클래스 정의가 평가되면 개발자가 작성한 constructor 메서드에 기술된 동작을 하는 함수 객체가 생성되는 것입니다.
참고로, constructor 메서드를 생략하면 다음과 같은 빈 constructor가 암묵적으로 적용됩니다.

class Person {
  constructor() { }
}

프로토타입 메서드

클래스의 프로토타입 객체에 메서드를 추가하려면 생성자 함수 사용 방식과는 다르게 다음과 같이 클래스 블럭 내부에서 메서드 축약표현을 쓰면 됩니다.

class Person {
  constructor(name){
    this.name = name;
  }
    
  sayHi(){
    console.log(`Hi, my name is ${this.name}!`);
  }  
}

const me = new Person('Kenny');
me.sayHi();  // Hi, my name is Kenny!

정적 메서드

정적 메서드는 클래스 몸체에서 static 키워드를 사용하여 선언할 수 있습니다. 생성자 함수에서 정적 메서드를 만드려면 [생성자함수이름].[정적메서드이름] = (정적메서드 내용)과 같이 번거로웠지만, 클래스는 static 키워드 하나면 간편하게 정적 메서드를 추가할 수 있습니다.

class Person {
  constructor(name){
    this.name = name;
  }
    
  sayHi(){
    console.log(`Hi, my name is ${this.name}!`);
  }  
  
  static sayHello(){
    console.log('Hello!');
  }
}

Person.sayHello();  // Hello!

다이어그램

위의 Person 클래스를 만들어 constructor, 프로퍼티 메서드, 정적 메서드를 추가한 뒤 me라는 인스턴스를 만들면 메모리상에는 다음과 같은 관계가 형성됩니다.

class 상속

자바스크립트의 클래스는 extends 키워드를 사용히여 확장 가능합니다. 여기서 확장이란 자바스크립트에서 클래스 키워드를 사용해서 상속을 구현하는 특별한 행위입니다. 프로토타입 기반의 상속과 클래스 기반 상속의 차이점과 클래스에서 확장에 의한 상속이 어떤 의미인지 알아보겠습니다.

클래스 상속과 생성자 함수 상속

클래스는 확장해서 상속할 수 있습니다. 기존의 프로토타입 기반 상속은 프로토타입 체인을 통해 다른 객체릐 자산을 상속받는 매커니즘인 반면, 확장에 의한 클래스 상속은 기존 클래스를 상속받아 새로운 클래스를 확장하여 정의하는 것입니다. 다음 코드는 Animal이라는 클래스를 상속받은 Bird와 Lion 클래스를 정의하고 사용하는 예제 코드입니다.

class Animal {
  constructor(age, weight){
    this.age = age;
    this.weight = weight;
  }
  
  eat(){
    return 'eat';
  }
  
  move(){
    return 'move';
  }
}

// 상속을 통해 Animal 클래스를 확장한 Bird, Lion
class Bird extends Animal {
  fly(){
    return 'fly';
  }
}

class Lion extends Animal {
  attack(){
    return 'attack';
  }
}

const bird = new Bird(10, 8);
const lion = new Lion(5, 60);

하지만 확장에 의한 상속 역시 다이어그램으로 표현해보면 아래와 같이 내부적으로는 프로토타입 체인을 통해 상속이 구현되어있음을 알 수 있습니다.

자바스크립트 객체지향

지금까지 클래스 문법과 클래스 기반 상속을 알아보았습니다. 자바스크립트의 클래스라는 키워드는 기존 클래스 기반 객체지향 언어들에 익숙한 사람들을 위해 탄생한 일종의 문법적 설탕이라는 것을 알 수 있었습니다. 그러면 이제부터 객체지향 프로그래밍을 잘하기 위한 원칙들을 알아보겠습니다.

Polymorphism

Polymorphism이란 다형성이라고 흔히 직역해서 사용합니다. 객체지향에서 하나의 클래스가 여러 동작을 할 수 있다는 의미로 통용되는 단어입니다. 이번에는 이 다형성을 이루는 두 가지 조건인 대체가능성과 내적일관성에 대해 알아보겠습니다.

다음 코드를 보죠.

const Worker = class {
  run(){ console.log("working")}
  print(){ this.run() }
}

const Hardworker = class {
  run(){ console.log("hard working")}
}

const worker = new Hardworker();
console.log(worker instanceof Worker);
worker.print();

대체가능성

자식클래스는 부모클래스를 대체할 수 있다는 특징이 대체가능성입니다. js에서는 이러한 대체가능성을 instanceof 키워드로 확인할 수 있습니다.

내적일관성

내적일관성이란 객체를 생성할 때 해당 객체가 어떤 클래스의 constructor로 생성되었는가에 따라 객체의 본질이 결정되는 특성입니다. 위의 예제에서 worker.print()문은 Hardworker의 run메서드를 실행하게 됩니다. worker객체의 본질은 HardWorker클래스이기 때문입니다.

대체가능성과 내적일관성 모두 자바스크립트라는 언어가 약속한 규약입니다. 위 두 특성을 가지는 언어를 다형성을 따른다고 합니다. 그리고 어떠한 언어가 객체지향 언어라는 것은, 다형성, 즉 대체가능성과 내적일관성을 따른다는 말과 동일합니다.

0개의 댓글