요즘 사람들 사이에서 와플 메이커가 유행이다. 크루아상 생지를 올려서 크로플을 만들기도 하고 삼각김밥이나 인절미 등을 통해서 삼각김밥 와플, 인절미 와플 등을 만들기도 한다. 여러가지를 뚝딱뚝딱 만드는 와플메이커 같은 역할을 할 수 있는게 바로
Class
이다.
객체지향 프로그래밍이라는 말이 있다. 프로그램을 객체를 통해서 구성하고 각 객체들의 상호작용을 통해서 프로그램이 돌아갈 수 있도록 하는 것이다. 객체는 object
를 말하는데, 이에 대해서는 다음에 더 정리해보려고 한다.
class
는 객체지향 프로그래밍의 핵심 중에 하나라고 할 수 있다. object
를 빠르고 쉽게 만들 수 있도록 도와주기 때문이다. class
의 경우에 ES6에서 새롭게 추가되었는데 프로토타입 기반의 JavaScript
에 아예 새로운 기능이 추가된 것이 아니라 함수의 일종으로 문법적인 편의성을 준 것이라고 생각하면 된다. 즉, syntactical sugar 라고 한다. 말 그대로 프로토타입 기반의 JavaScript
를 사용하면서 객체지향 프로그래밍을 하기 위해 머리 아프지 말고 달콤하게 사용하라는 뜻이다.
(정말 감사합니다 😃😃😃)
// 기본 문법
class Person {
// constructor
constructor(name, age) {
// fields
this.name = name;
this.age = age;
}
// methods
speak() {
console.log(`${this.name}: hello!`);
}
}
위는 Person
이라는 class
를 만든 예시이다. class
는 object
를 만드는 역할을 하기 때문에 생성자(constructor)
를 정의해 주어야 한다. 생성자는 말 그대로 만들려는 object
에 어떤 field
를 넣을 지를 결정한다. field
는 object
가 가질 정보라고 생각하면 된다.
마지막으로 method
의 경우에는 object
가 가지게 될 함수이다. 위에서는 간단하게 speak()
라는 함수를 넣어주었다.
구조를 보면 class
나 object
가 낯설지 않음을 느끼게 됐을 것이다. 간단하게 사람이라는 예시를 보자. 이 글을 쓰는 나는 이름으로 cheoljin
을 가지고 있고 성별로는 남자
를 가지고 있다. 가지고 있는 능력으로는 책읽기
, 대화하기
등이 있다. 이를 클래스로 표현하면 아래와 같을 것이다.
class 한국사람 {
constructor(이름, 성별){
this.이름 = 이름;
this.성별 = 성별;
}
책읽기(){
책을 읽습니다.
}
대화하기(){
대화를 합니다.
}
임의로 한국남자
라는 class
를 생성했다. 여기에 몇가지 정보를 통해서 철진
이라는 object
를 만들 수 있다.
const 철진 = new 한국남자("철진", "남자");
방금 작업을 통해서 class
의 instance
인 철진
이 만들어졌다. instance
는 class
를 통해 생성된 object
를 뜻한다. 이처럼 class
와 object
는 현실의 물체들의 구조와 닮아있기 때문에 유용하게 사용될 수 있다.
class
는 쉽게 여러 object
를 만들 수 있도록 해주기 때문에 매우 편리하다. 그런데, 누군가가 이 class
에 잘못된 정보를 넣어서 object
를 만든다면 어떻게 될까?
class 한국사람 {
constructor(이름, 성별, 나이){
this.이름 = 이름;
this.성별 = 성별;
this.나이 = 나이;
}
책읽기(){
책을 읽습니다.
}
대화하기(){
대화를 합니다.
}
이런 class
가 있다고 해보자. 그런데 이를 사용하는 누군가가 마지막 필드인 나이에 -20이라는 숫자를 잘못 넣었다고 생각해보자. 그렇게 되면 나이가 -20인 말이 안되는 인스턴스가 생성될 것이다. 이런 일들을 방지하기 위해서 우리는 필드에 접근하느 경우에 제한을 걸 필요가 있다. 이 때 사용하는 것이 바로 getter
와 setter
이다.
class 한국사람 {
constructor(이름, 성별, 나이) {
this.이름 = 이름;
this.성별 = 성별;
this.나이 = 나이;
}
get 나이() {
return this._나이;
}
set 나이(value) {
// if (value < 0) {
// throw Error("나이는 0보다 작을 수 없습니다!!");
// }
this._나이 = value < 0 ? 0 : value;
}
}
위를 보자. 생성자 아래에 get
과 set
을 작성했다. get
과 set
은 accesor property
로 값을 반환받거나 설정할 때 사용되는 함수이다.
차근차근 어떻게 사용되는지 살펴보자. 우선 get
의 경우에는 한국사람.나이
이 사용되는 경우에 호출이 되면서 나이를 반환해준다. 즉 한국사람.나이
를 사용했을 때 필드에 직접적으로 접근하게 되는 것이 아니라 get 나이()
가 실행된다는 뜻이다.
set
의 경우에는 한국사람.나이 = value
를 실행할 때 호출된다. 즉 값을 직접적으로 할당하는 것이 아니라 set 나이(value)
가 실행된다는 뜻이다. 그렇기 때문에 맞지 않는 값을 넣었을 때 에러 메세지를 보내거나 다른 값을 대신 넣도록 할 수 있다.
class
에는 또 다른 어썸한 능력이 있다. 바로 상속
이다. 예를 들어 도형
이라는 클래스가 있다고 해보자. 이 도형이라는 클래스는 기본적으로 너비
, 높이
, 색
이라는 필드를 가지고 있고 그리기()
라는 메소드를 통해서 도형을 그려낼 수 있고 넓이()
라는 메소드를 통해 넓이 값을 구할 수 있다고 가정하자.
class 도형 {
constructor(너비, 높이, 색) {
this.너비 = 너비;
this.높이 = 높이;
this.색 = 색;
}
그리기() {
}
넓이() {
return this.너비 * this.높이;
}
}
이렇게 만들었다. 하지만 아직 아쉬운 점이 많다. 도형이라는 큰 클래스를 만들기는 했지만 사각형이나 삼각형, 붕어빵 모양 등의 도형을 만들고 싶을 때 바로 사용할 수 없기 때문이다. 각자의 특징에 맞게 만들고 싶다면 사각형이라는 클래스를 만들고 삼각형이라는 클래스를 또 만들고 붕어빵 클래스까지 만드는 작업을 반복해야 할 것이다. 하지만, 상속
덕분에 그런 작업을 반복하지 않아도 된다.
class 사각형 extends 도형 {}
짜잔! 🎉 방금의 동작을 통해 사각형의 class
가 생성됐다.
class 삼각형 extends 도형 {
넓이(){
return (this.너비 * this.높이)/2;
}
}
이렇게 삼각형의 class
를 만들 수도 있다. 이 때, 넓이()
라는 메소드를 다시 정의해주었다. 삼각형의 경우에는 넓이를 구하는 방식이 다르기 때문이다.
이처럼 extends
를 통해서 class
를 상속시키는 경우에 메소드를 다시 정의해 주면서 다양성을 추구할 수 있고 특별히 선언하지 않은 경우에는 원형의 class
가 가지고 있던 필드나 메소드를 그대로 상속시킬 수 있다. 클래스는 정말 어썸하다✨
참고자료:
드림코딩 by 엘리