Web Front-end/JavaScript

[JS/Basic/객체] 자바스크립트의 클래스

JavaScript에서 객체를 구현하는 방법은 아주 많습니다.

  • 객체 리터럴을 이용해서 선언
  • Factory 함수를 이용해서 객체 리터럴로 반환
  • 생성자 함수를 이용해서, 객체를 선언한 뒤, new로 할당

위의 3가지 방법 외에도 , ES6에서 정의된 방법이 1개가 있습니다. 어쩌면 가장 친숙한(?) 방법일지도 모릅니다. 바로 Class 문법입니다. 각각의 방법마다 차이점은 있긴 합니다! 하지만, 그건 OOP 디자인패턴을 다루면서 더욱 자세히 하겠습니다.(Prototype에 대한 심화설명 + 다양한 패턴에서 Prototype의 쓰임, TypeScript의 등장 등등) 


Class

  • Constructor(생성자)와 new를 이용해서, 객체를 생성합니다.
  • method를 정의해서 사용할 수 있습니다. 
  • 사실 Game이라는 함수를 생성하게 됩니다(?)
class Game{
	constructor(){} //생성자
    method1(){}
    method2(){}
    ...
	
}

game = new Game();

 

위의 문법도 대부분의 상황에서는 Factory 함수를 쓰든 , 생성자 함수를 쓰든 상관이 없을겁니다. 하지만, class 문법과 생성자 함수가 같다면, var을 let과 const로 대체한 것처럼 완벽히 대체되었겠죠! 미묘한 차이가 있습니다. 

자바스크립트의 클래스 원리

클래스의 선언(declare)부분

class Game{
	constructor(){
    	...
    }
    method1(){
    	...
    }
}

console.log(typeof Game); //function 

console.log(Game === Game.prototype.constructor); //true

Game();//error
  • Game이라는 함수를 만듭니다. 함수의 내용(로직)은 constructor에 정의되어 있는 부분을 가져옵니다. 
  • 클래스 내에서 정의한 메서드를 Game.prototype에 저장합니다.
  • 클래스로 만든 함수에는 내부 프로퍼티인 [[IsClassConstructor]] :true로 붙게됩니다. 따라서, 일반함수처럼 호출이 불가능해집니다.
  • 클래스는 항상 엄격모드로 실행 됩니다.(use strict)

클래스의 "할당"(allocation)부분

  • new로 Game이라는 함수가 불려지는 순간, Game이라는 객체 리터럴을 만들게 되고, 메서드들은 Game.prototype을 참조하는 형태로 만들어집니다.

그림으로 표현하면, 아래와 같이 됩니다.

 

클래스와 생성자 함수의 차이점

  • 클래스로 만든 함수에는 내부 프로퍼티인 [[IsClassConstructor]] :true로 붙게됩니다. 따라서, 일반함수처럼 호출이 불가능해집니다.
  • 클래스는 항상 엄격모드로 실행 됩니다.(use strict) 따라서, this가 undefined가 기본이 되겠죠?

주의점)

  • 비동기 함수로 메소드를 넘길 때, 메소드 내부에 this가 있다면 원하는 코드가 나오지 않습니다. JS의 this는 호출할 때, 결정이 되기 때문에 비동기 함수와 같이 쓰게 된다면 의도치 않은 결과를 낼 수 있습니다.
class Button{
	constructor(value){
    	this.value=value;
    }
    click(){
    	console.log(this.value);
    }
}

const btn = new Button("hello!");

setTimeout(btn.click,1000); //undefined?  or hello!

위의 코드는 undefined입니다. 따라서, btn.click을 보면 아직 "호출"을 안해줘서 문제가 생긴겁니다. 

class Button{
	constructor(value){
    	this.value=value;
    }
    click(){
    	console.log(this.value);
    }
}

const btn = new Button("hello!");

setTimeout(()=>btn.click(),1000); //undefined?  or hello!

비동기 함수에서 method losing this 현상 방지하기

  • arrow function으로 반환하는 형태로 작성한다면 , 이미 click()은 Button 객체에 bind되었기 때문에, 우리가 의도한 대로 "hello!"가 나오게 됩니다.
  • Bind함수 (call,apply,bind)를 이용해도 됩니다.
  •  click() function 자체를 화살표 함수로 구현하는 방법도 있습니다. 단 , 화살표 함수는 Prototype을 생성하지 않기 때문에, 테스트 케이스 작성(mocking)이 불가능할 수 있습니다. 프로토타입이 없으니, 상속도 불가능하게 됩니다.