본문 바로가기
📌 Front End/└ JavaScript

[JavaScript] 자바스크립트 프로토타입 기반의 함수 Class (ES6)

by 쫄리_ 2023. 3. 10.
728x90
반응형

JavaScript 프로토타입 기반의 함수 Class

안녕하세요 !

오늘은 ES6에서 도입 된 Class에 대해 알아보겠습니다.

들어가기 전 이야기 드리고 싶은 부분이 있습니다.

JavaScript는 프로토타입 기반 객체 지향 언어입니다. 모든 객체는 각 부모 역할을 담당하는 객체와 prototype으로 연결이 되어 있다. 그렇기 때문에 class가 필요 없이도 객체 지향 프로그래밍이 가능하다. 어떤 커뮤니티에서는 JavaScript가 무슨 객체 지향 언어냐 라고 이야기를 하는 분들을 본 것 같은데 나는 그분들이 생각하는 다른 언어보다 상상 이상으로 충분한 조건을 갖추고 있는 객체 지향 언어라고 생각한다.

이제 본격적으로 시작해보자.

class 는 어떤 것을 제공 해주나 ?

기존 prototype 기반의 상속 보다 명료하게 구현해 놓았으며 객체를 생성하고 상속을 다루는데 있어 조금 더 명확한 문법 들을 제공해 줍니다. 

여기서 절대로 오해하면 안된다. 기존 JavaScript에 새로운 객체지향 상속 모델이 추가된 게 아니라 모든 것은 prototype 기반으로 연결되어 있으며, 결국 class도 하나의 함수다. class도 함수 이며, 함수도 함수 표현식, 함수 선언을 이용하여 정의할 수 있듯이 class도 class 표현식, class 선언을 이용하여 정의 할 수 있다.

1. Class 선언

class 이름과 함께 class 키워드를 통해 정의합니다.

class Chicken {

constructor(price, brand) {

this.price = price;

this.brand = brand;

}

}

잠깐 ! 여기서 잠시 생각해보자. Class가 위에서 함수라고 했는데 기존 함수 선언의 경우 호이스팅이 일어나서 ReferenceError가 나야하는데 왜 안나지 ? 라는 의문을 가져야한다. class도 letconst와 마찬가지로 선언 후 일시적 사각지대(TDZ)로 빠져서 호이스팅이 안되는 것처럼 보인다.

2019/02/19 - [넌 누구야 JavaScript 공부/JavaScript] - let, const 란? 그리고 왜 써야만 하는가?

const chicken = new Chicken(); // ReferenceError

class Chicken {}

2. Class 표현식

함수와 비슷한 표현 방식으로 class 이름을 가질 수 있고 갖지 않을 수도 있습니다.

// 이름을 갖지 않을 때

let Chicken = class {

constructor(price, brand) {

this.price = price;

this.brand = brand;

}

};

// 이름을 가질 때

let Chicken = class Chicken {

constructor(price, brand) {

this.price = price;

this.brand = brand;

}

};

이제 바깥쪽을 보았으니 안쪽으로 들어가보자.

class body({} - 중괄호 안쪽)와 method에 대해 보자.

class body 에는 기본적으로 strict mode 에서 실행됩니다.

1. Constructor

class로 생성된 객체를 생성하고 class 프로퍼티를 초기화 하기 위한 메소드이다. 특징으로는 class 내부에 한개 밖에 존재할 수 없으며, 새로 counstructor 하나를 추가한다면 SyntaxError 가 발생한다.

class Chicken {

constructor(price) {

this.price = price;

}

}

const chicken = new Chicken(23000);

console.log(chicken); // Chicken { price: 230000 }

추가적으로 Constructor는 생략 가능하며, 생략 시 constructor(){} 를 포함한 것과 동일하게 작동한다. 

// constructor 생략

class Chicken {}

// constructor 생략 x

class Chicken {

constructor() {}

}

2. static 메소드

class를 위한 static 메소드를 정의 할 수 있습니다. class의 인스턴스에서 호출할 수 없고 class 이름으로 호출한다. 즉 static 메소드는 인스턴스 생성 없이 호출가능하다.

class Wallet {

constructor(money) {

this.money = money;

}

staticisSuccess(foodPrice) {

return this.money >= foodPrice;

}

}

const park = new Wallet(17000);

console.log(Wallet.isSuccess(23000)); // false

슬프지만 위의 예제를 보니 오늘 치킨은 못 먹을 것 같다. 

3. getter, setter

class 내부 프로퍼티를 접근하기 위하여 값을 조작하거나 할당해야 하는 일이 있이 있는데 getter와 setter를 이용하면 된다. getter는 무언가를 받을 때 사용하고 setter는 무언가를 할당할 때 사용한다. 

class Wallet {

constructor(money) {

this._money = money;

}

// Getter

getisCanEat() {

return this._money >=0;

}

// Setter

setisCanEat(foodPrice) {

return this._money = this._money - foodPrice;

}

}

const PARK = new Wallet(17000);

PARK.isCanEat = 23000;

console.log(PARK.isCanEat); // false

다시 밖으로 나와서 Extends(상속)에 대해서 알아봅시다 !

class 상속은 다른 언어에서도 많이 유용하게 사용중이며, 장점은 코드 재사용성이다. 상속을 통해 기존에 구현한 class와 새로 구현하는 class가 유사하다면 상속을 통해 기존의 구현한 class를 상속 받은 후 다른 점만 구현 하면 된다. 

// 부모 class

class Wallet {

constructor(money) {

this._money = money;

}

// 지갑에 있는 돈 가져오기

getMoney() {

return this._money;

}

setMoney(foodPrice) {

return this._money = this._money - foodPrice;

}

isMoneyExist() {

return this._money >0;

}

}

// 자식 class

class Person extends Wallet {

constructor(money, foodPrice) {

super(money);

this._foodPrice = foodPrice;

}

// 음식 구매

buyFood() {

// 돈이 없거나 가지고 있는 돈보다 음식 값이 비쌀 때

if (!super.isMoneyExist() && (super.getMoney() - this._foodPrice) <0) {

returnfalse;

}

// 음식 구매

super.setMoney(this._foodPrice);

returntrue;

}

}

const PARK = new Person(23000, 17000);

console.log(PARK.buyFood() ? `음식 구매가 완료되었습니다. 구매 후 ${PARK.getMoney()}원 남았습니다.` : '지갑에 돈이 없거나 부족합니다. 지갑을 확인해주세요.');

class 를 상속 할 때에는 extends 를 사용하여 상속을 한다. 위의 예시는 부모 class Wallet을 자식 class Person이 상속받은 예시이다. 자식 class Person은 부모 class Wallet의 메소드를 모두 사용할 수 있게 되었으며, 메소드를 따로 오버라이딩 하여 자식 class에서 재 정의가 가능하다.

위의 예시를 보면 super 키워드가 여기저기에 쓰인 것을 볼 수 있다. super 키워드는 부모 class Wallet을 참조할 때 부모 class의 constructor를 호출할 때 사용한다. 이 말은 즉 super를 사용하면 부모 class의 contructor가 호출된다는 이야기이다. super는 부모 class 프로퍼티 또는 메소드를 참조하기 위해 사용하며, 자식 class constructor에서 super()를 호출하지 않으면 this에 대한 참조 에러가 난다.

// 부모 클래스

class Wallet {}

// 자식 클래스

class Person extends Wallet {

// ReferenceError : this 선언 전 super()를 호출해야 한다.

constructor() {}

}

const PARK = new Person();

728x90
반응형