[mjt] 클래스와 기본 문법을 알아보자
클래스와 기본 문법을 알아보자
클래스란
아래의 코드를 예시로 이해해보자.
class User {
constructor(name) {
this.name = name;
}
sayHi() {
alert(this.name);
}
}
// User가 함수라는 증거
alert(typeof User); // function
class User {...}
문법 구조가 하는 일은 아래와 같다.
-
User
라는 이름을 가진 함수를 만든다. 함수 본문은 생성자 메서드constructor
에서 가져오며, 생성자 메서드가 없으면 본문이 비워진 채로 함수가 만들어진다. -
sayHi
같은 클래스 내에서 정의한 메서드를User.prototype
에 저장한다.
new User
를 호출해 객체를 만들고, 객체의 메서드를 호출하면 함수의 prototype 프로퍼티에서 설명한 것처럼 메서드를 prototype 프로퍼티를 통해 가져오고 이 과정이 있기에 객체에서 클래스 메서드에 접근할 수 있는 것이다.
클래스 기본 문법
클래스는 class
키워드를 사용해 정의할 수 있으며, constructor
메서드를 통해 객체 초기화를 수행한다.
2-1) 기본 클래스 선언
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name}이(가) 소리를 냅니다.`);
}
}
const dog = new Animal("강아지");
dog.speak(); // "강아지가 소리를 냅니다."
클래스는 단순한 편의 문법이 아니다.
class
라는 키워드 없이 클래스 역할을 하는 함수를 선언할 수 있기 때문에 클래스
는 ‘편의 문법’에 불과하다고 이야기한다. 참고로 기능은 동일하나 기존 문법을 쉽게 읽을 수 있게 만든 문법을 편의 문법(syntactic sugar, 문법 설탕)이라고 한다.
// class User와 동일한 기능을 하는 순수 함수를 만들어보겠습니다.
// 1. 생성자 함수를 만듭니다.
function User(name) {
this.name = name;
}
// 모든 함수의 프로토타입은 'constructor' 프로퍼티를 기본으로 갖고 있기 때문에
// constructor 프로퍼티를 명시적으로 만들 필요가 없습니다.
// 2. prototype에 메서드를 추가합니다.
User.prototype.sayHi = function () {
alert(this.name);
};
// 사용법:
let user = new User("John");
user.sayHi();
위의 예시처럼 순수 함수로 클래스 역할을 하는 함수를 선언하는 방법과 class
키워드를 사용하는 방법의 결과는 거의 같다.
3-1) 함수 클래스와 클래스의 차이
-
class
로 만든 함수엔 특수 내부 프로퍼티인[[IsClassConstructor]]
:true
가 이름표처럼 붙는다. 이것만으로도 두 방법엔 분명한 차이가 있음을 알 수 있다. 자바스크립트는 다양한 경우에[[IsClassConstructor]]
:true
를 활용합니다. 클래스 생성자를 1와 함께 호출하지 않으면 에러가 발생하는데 이 때[[IsClassConstructor]]
:true
가 사용된다. - 클래스에 정의된 메서드는 열거할 수 없다(non-enumerable). 클래스의
prototype
프로퍼티에 추가된 메서드의enumerable
플래그는false
입니다.for..in
으로 객체를 순회할 때, 메서드는 순회 대상에서 제외하고자 하는 경우가 많으므로 이 특징은 꽤 유용하다. - 클래스는 항상 엄격 모드로 실행된다(use strict). 클래스 생성자 안 코드 전체엔 자동으로 엄격 모드가 적용된다.
클래스 표현식
클래스 또한 함수처럼 다른 표현식 내부에서 정의, 전달, 반환, 할당할 수 있다.
// 클래스 표현식 예시
let User = class {
sayHi() {
alert("hi");
}
};
4-1) 기명 클래스 표현식
- 기명 함수 표현식과 유사하게 클래스 표현식에도 이름을 붙일 수 있다.
- 클래스 표현식에 이름을 붙이면, 이 이름은 오직 클래스 내부에서만 사용할 수 있다.
// 기명 클래스 표현식(Named Class Expression)
// (명세서엔 없는 용어이지만, 기명 함수 표현식과 유사하게 동작한다.)
let User = class MyClass {
sayHi() {
alert(MyClass); // MyClass라는 이름은 오직 클래스 안에서만 사용할 수 있다.
}
};
new User().sayHi(); // 원하는대로 MyClass의 정의를 보여준다.
alert(MyClass); // ReferenceError: MyClass is not defined, MyClass는 클래스 밖에서 사용할 수 없다.
4-2) 클래스를 동적으로 생성
필요에 따라 동적으로 생성하는 것도 가능함
function makeClass(phrase) {
// 클래스를 선언하고 이를 반환함
return class {
sayHi() {
alert(phrase);
}
};
}
// 새로운 클래스를 만듦
let User = makeClass("안녕하세요.");
new User().sayHi(); // 안녕하세요.
getter와 setter
리터럴을 사용해 만든 객체처럼 클래스도 getter
나 setter
, 계산된 프로퍼티를 지원한다. get
과 set
을 이용해 user.name
을 조작할 수 있게 해보자.
class User {
constructor(name) {
// setter를 활성화합니다.
this.name = name;
}
get name() {
return this._name;
}
set name(value) {
if (value.length < 7) {
alert("이름이 너무 짧습니다.");
return;
}
this._name = value;
}
}
let user = new User("rarrit");
alert(user.name); // rarrit
user = new User(""); // 이름이 너무 짧습니다.
클래스 필드
클래스 필드는 최근에 더해진 기능으로 구식 브라우저에선 폴리필이 필요할 수 있다.
- ‘클래스 필드(class field)’라는 문법을 사용하면 어떤 종류의 프로퍼티도 클래스에 추가할 수 있다.
class User {
name = "rarrit";
sayHi() {
alert(`${this.name}님 안녕하세요!`);
}
}
new User().sayHi(); // rarrit님 안녕하세요!
클래스를 정의할 때 <프로퍼티 이름> = <값>
을 써주면 간단히 클래스 필드를 만들 수 있으며, 중요한 특징 중 하나는 User.prototype
이 아닌 개별 객체에만 클래스 필드가 설정된다는 점이다.
class User {
name = "rarrit";
}
let user = new User();
alert(user.name); // rarrit
alert(User.prototype.name); // undefined
6-1) 복잡한 표현식 및 함수 호출 결과 사용
클래스 필드엔 복잡한 표현식이나 함수 호출 결과를 사용할 수 있다.
class User {
name = prompt("이름을 알려주세요.", "rarrit");
}
let user = new User();
alert(user.name); // rarrit
6-2) 클래스 필드로 바인딩 된 메서드 만들기
자바스크립트의 this
는 동적으로 결정되며 객체 메서드를 여기저기 전달해 전혀 다른 컨텍스트에서 호출하게 되면 this
는 메서드가 정의된 객체를 참조하지 않는다. 아래의 예시를 보자
class Button {
constructor(value) {
this.value = value;
}
click() {
alert(this.value);
}
}
let button = new Button("안녕하세요.");
setTimeout(button.click, 1000); // undefined
// 해결 방법
class Button {
constructor(value) {
this.value = value;
}
click = () => {
// 화살표 함수 사용
alert(this.value);
};
}
let button = new Button("안녕하세요.");
setTimeout(button.click, 1000); // 안녕하세요.
정리
-
클래스 개념
- 생성자 함수보다 직관적인 문법으로
prototype
기반 메서드를 정의. - 내부적으로 함수이며,
new
없이 호출 불가.
- 생성자 함수보다 직관적인 문법으로
-
주요 특징
-
constructor
로 객체 초기화, 메서드는 자동prototype
저장. - 내부 엄격 모드 적용, 메서드는 열거되지 않음.
-
-
클래스 필드 & getter/setter
- 필드는 개별 객체에 저장되어
prototype
과 독립적. -
get/set
으로 속성 제어 가능, 화살표 함수 사용 시this
고정.
- 필드는 개별 객체에 저장되어