요즘 노마드코더로 타입스크립트를 공부하고 있는데, Classes and Interfaces이라는 단원이 있다.
현재 이 강의를 들으며 타입스크립트 챌린지도 같이 병행하고 있는데 Geolocation Api에 대한 추상 클래스와 제네릭을 만드는 것이 과제였다. 근데 과제를 하면서 지금까지 클래스를 제대로 사용해본 적이 없어서🥲... 제대로 하고 있다는 느낌이 안들었다! 제대로 써본적이 없어서 클래스에 대한 개념이 명확하게 정립되지 않은 것 같다. 정리를 해볼 필요성이 있다고 느꼈다.
제가 공부하면서 이해한 점들을 포스트로 작성해봤습니다. 최대한 전체적으로 이해하면서 정리해보려고 했는데 틀린 점이 있을 수도 있어요. 틀린 점을 발견해주셨다면 알려주시면 감사하겠습니다.😊
클래스야말로 객체 지향 프로그래밍 그 자체에서 사용하는 대표적인 문법이라고 할 수 있을 것 같다. 일명 OOP(Object-Oriented-Programming)라고도 불리는 객체 지향 프로그래밍은 C#, 자바 등에만 있는 개념이었으나 ES6 이후 자바스크립트에도 제대로 포함되었다. 원래 없었다가 자바스크립트 버전이 업그레이드 되면서 추가된 문법인 것이다.
그리고 현재 타입스크립트가 등장하면서 자바스크립트에서는 사용할 수 없었던 더 다양한 타입 보호와 readonly
, private
, protect
등의 문법으로 거의 다른 객체지향 프로그래밍에서 쓸 수 있는 문법을 거의 다 쓸 수 있게 되었다!
객체 지향 프로그래밍 현재 많은 기업들에서 채택하고 있는 설계 방법이라고 한다. 우아한 형제들에서도 기술 블로그에 프로그램에 객체 지향 프로그래밍를 사용한 글이나 유튜브에 테크 세미나 영상도 올라왔다. 객체 지향 프로그래밍을 제대로 파기 위해서는 대표적인 문법인 클래스를 공부하지 않을 수 없다.
클래스는 그러니까 자주 쓸 객체의 템플릿이라고 할 수 있다. 자바스크립트에서 배열 또한 객체의 일부분일만큼 객체는 다양한 자료형을 담을 수 있다. 그리고 이 객체가 어떤 형태여야 하는지 그 형태를 정해준 것이 바로 클래스이다.
여기서 자바스크립트를 아주 초반 공부할 때, 객체의 형태를 언제, 어떨때 정해줘야 하는 것인지 의문이 들 때가 있었다. 이것 역시 클래스 문법을 많이 안써봤기 때문에 든 의문이었다.
A. 동일한 키를 가진 객체를 자주 쓸 때가 있다. 동일한 키에 값만 달라진다면 계속 똑같은 객체를 생성하는 것은 유지보수 측면에서 별로 좋지 않다고 한다. 오타로 잘못된 코드를 작성한다든가, 필요한 요소를 빼먹는다든가 할 수 있기 때문이다.
클래스를 사용할 대표적인 예로 유저 데이터 정보를 생각해볼 수 있겠다.
A라는 유저의 데이터가 들어있는 객체는 "이름", "나이", "취미" 라는 데이터가 필요하다고 해보자. 그럼 아래와 같이 객체를 만들 수 있다.
const UserA = {
name: "jellie",
age: "100",
hobby: "책읽기"
}
그런데 유저는 A만 있지 않다. 다수의 유저가 생성된다면 이렇게 키는 같지만 값이 다르기 때문에 유저의 데이터를 사용하려면 객체를 만들어주긴 해야 한다. 그렇지만 모든 유저의 객체를 짜는 것은 정말 비효율적일 것이다. 위에서 말했듯 에러의 위험성도 커진다.
그래서 클래스를 통해 한 객체에 어떤 데이터들이 담겨져 하는지 그 형태를 작성해주고, 그 클래스를 불러오기만 하면 되는 것이다. 이렇게 같은 종류(그러니까 같은 키를 가진?)에 속하는 객체라면 클래스로 만들어주는 것이 유지보수관리 측면에서 효율적이다.
그러니까 클래스는 비슷한 정보들이 담긴 객체를 뽑아내는 공장이라고 생각하면 될 것 같다.
문법을 살펴보기 전에 먼저 클래스는 어떤 특징들을 갖고 있는지 살펴봤다.
추상 자료형이란 자료 표현과 자료형의 연산을 캡슐화한 것을 말한다. 캡슐화란 밖에서 내부 구조가 어떻게 생겼는지 알지 못하고 사용하는 것으로 이해했다. 그러니까 마치 자동차의 내부 기계 구조를 몰라도 인터페이스를 통해 우리가 운전을 할 수 있는 것처럼 말이다. 클래스는 내부 형태가 어떻게 생겼는지 몰라도 몇개의 키워드로 우리는 클래스를 마구 이용할 수 있다.
객체는 추상 자료형의 인스턴스라고 생각하면 된다.
추상 자료형에서 정의된 연산을 메소드, 메소드의 호출을 생성자라고 한다.
class User {
constructor(name) { // 객체의 기본상태를 설정해주는 생성자 메서드
this.name = name; // name 인수가 this.name에 할당됨
}
sayMyName() {
alert(this.name); // constructor에 의해 할당된 this.name을 클래스 내부에서 사용할 수 있음.
}
}
let user = new User("jellie")
user.sayMyName();
new User("jellie")
를 호출하면 자바스크립트에서는 new 연산자에 따라 새로운 객체가 생성된다. 그리고 "jellie"
라는 인수를 받아 constructor
를 자동으로 실행한다. constructor
는 클래스에서 자동으로 실행되는 생성자함수이며, method
는 객체의 prototype에 저장되어 호출되는 함수인 것이다. 여기서 기억해야 할 점은 class User는 contructor함수와 같다는 점이다. 물론 완전 똑같지는 않겠지만 자바스크립트에서 클래스는 일단 함수고, 함수 본문을 constructor에서 가져온다는 점에서 동일시할 수 있다.
constructor에 대해 더 자세히 알아봐야할 것 같다. 그러니까 메소드 함수와는 다르고, 클래스의 초기 함수로 자동으로 실행된다는 건데, 정확히 어떻게 사용되는 건지는 잘 이해가 안됐다.
constructor
를 사용하면 다른 모든 메서드 호출보다 앞선 시점인, 인스턴스 객체를 초기화할 때 수행할 초기화 코드를 정의할 수 있습니다. - MDN
자바스크립트에서 클래스는 함수다. 거기서 constructor는 클래스라는 함수의 초기 코드는 정의해주는 역할을 맡는다. 그래서 constructor 생성자를 정의하지 않아도 빈 코드의 기본 생성자를 사용한다고 한다. constructor() {}
이렇게 빈 코드의 constructor함수가 실행되는 것이다.
✔️ 인스턴스 객체를 초기화 동작이 필요할 때
✔️ 다른 클래스를 상속하는 경우 (extends
)
super()
로 호출하고 그 뒤에 this
를 사용하면 된다.✔️ 프로퍼티의 값이 정해졌을 때(클래스 필드)
값이 동적으로 바뀔 때는 constructor로 동적으로 변경되는 값을 사용할 수 있게 만들어줘야 하지만 값이 정해져 있다면 굳이 함수로 값을 끌어올 필요가 없다. 주의할 점은 클래스 필드에서 정의되는 값은 Prototype에 저장되는 것이 아니라 객체에 저장된다!
예시)
class Category {
name = "도서"; // 프로퍼티 값을 지정해줌으로써 간단하게 클래스 필드를 만듦.
setCategory() {
alert(`${this.name} 카테고리로 설정되었습니다!`);
}
}
new Category().setCategory(); // 도서 카테고리로 설정되었습니다!
✔️ 동적으로 값이 들어가는 인수가 굳이 필요하지 않을 때
여기서 constructor
함수를 안써도 될 때는 method
에서 외부 인수를 받지 않아도 될때이다. 밖에서 값을 받아오지 않아도 되니 constructor로 인수를 내부로 가져오지 않아도 되는 것이다. 하지만 만약 set
같은 경우 인수가 필요하므로 내부로 인수를 끌어올 consturctor 함수를 적어줘야 한다.
그러니까 consturctor는 외부의 값을 클래스 내부에서 사용할 있도록 해주는, 초기 함수로 객체를 리턴해주는 함수라고 이해했다.
다음 포스트에는 상속, 오버라이딩 등에 대해 정리해봐야겠다...!
다음에 계속!
위키피디아: 객체 지향 프로그래밍
모던 자바스크립트: 클래스와 기본 문법
MDN: contstuctor
엘리의 드림코딩 유튜브: 클래스와 오브젝트의 차이점
코딩앙마: 클래스