클래스
클래스는 프로토타입의 문법적 설탕인가?
- js는 프로토타입 기반 객체지향 언어로, 클래스가 필요 없는 객체지향 프로그래밍 언어임
- 하지만 편의를 위해 ES6부터 클래스가 추가되었는데, 패러다임이 바뀐 것은 아니지만 기존의 프로토타입 기반 구현과 완벽히 동일하게 작동하진 않음
- 클래스와 생성자 함수의 차이
- 클래스는 호출시 new 연산자를 강제함
- 클래스는 상속을 지원하는 extends와 super키워드 제공
- 클래스는 호이스팅이 발생하지 않는 것처럼 동작함
- 클래스 내 코드는 암묵적으로 strict mode가 지정되고 해제할 수 없음
- 클래스의 constructor, 프로토타입 메서드, 정적 메서드는 모두 프로퍼티 어트리뷰트 [[Enumeralbe]]의 값이 false임
- 클래스는 단순한 문법적 설탕(기능은 동일한 편한 방식)이 아닌 새로운 객체 생성 메커니즘으로 볼 수 있음
클래스 정의
- class 키워드를 이용해 정의
- 생성자 함수와 같이 파스칼 케이스를 사용해 명명
- 일반적이진 않지만 함수와 같이 표현식으로 클래스 정의 가능, 이 때 무명 가능
- 클래스는 함수이므로 일급 객체임
- 클래스 몸체에 정의할 수 있는 메서드
- constructor (생성자)
- 프로토타입 메서드
- 정적 메서드
class Person {
constructor(name) {
this.name = name;
}
sayHi() {
console.log(`Hi! I'm ${this.name}.`);
}
static sayHello() {
console.log('Hello!');
}
}
const p1 = new Person('dlwlrma');
console.log(p1.name); // dlwlrma
p1.sayHi(); // Hi! I'm dlwlrma.
Person.sayHello(); // Hello!
메서드
constructor
- 클래스가 평가될 때 constructor의 내용을 가진 함수 객체가 생성됨
- constructor는 클래스 내에 유일해야 하고, 정의하지 않을 시 암묵적으로 빈 내용의 constructor를 생성함
- 프로토타입의 constructor와 이름만 같을 뿐 전혀 관계 없음
- constructor는 별도의 반환문을 갖지 않아야 함
- 명시적으로 객체 반환 시 암묵적 this반환이 무시되고 원시 값 반환 시 원시 값이 무시됨
프로토타입 메서드
- 클래스 몸체에서 정의한 메서드는 prototype 프로퍼티에 메서드를 추가하지 않아도 기본적으로 프로토타입 메서드가 됨
정적 메서드
- 클래스 몸체에서 static 키워드를 붙여 정의한 메서드는 정적 메서드가 됨
클래스의 인스턴스 생성 과정
- 인스턴스 생성 및 this 바인딩
- 빈 객체 생성, 프토토타입을 클래스의 prototype 프로퍼티가 가리키는 객체로 설정
- this에 해당 빈 객체 바인딩
- 인스턴스 초기화 : constructor 내부 코드 실행
- 인스턴스 반환 : 인스턴스가 바인딩 된 this 반환
프로퍼티
인스턴스 프로퍼티
- 인스턴스 프로퍼티는 원칙적으로는 constructor 내부에서 정의해야 함
- 최근 사양의 js에서는 클래스 필드를 허용
class Person {
constructor(){
this.name = 'lee';
}
}
const p1 = new Person();
console.log(p1.name); // lee
// 최근 사양의 js
class Person {
name = 'lee';
}
const me = new Person();
console.log(me.name); // lee
접근자 프로퍼티
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
get fullName() {
console.log(`${this.firstName} ${this.lastName}`);
}
set fullName(name) {
[this.firstName, this.lastName] = name.split(' ');
}
}
const p1 = new Person('myeongsuk', 'lee');
p1.fullName; // myeongsuk lee
p1.fullName = 'wlrma dl';
p1.fullName; // 'wlrma dl'
private필드 정의
- 최근 사양의 js에서는 private 필드 정의 가능
- 선언이나 참조할 때 식별자 선두에 #을 붙임
- 반드시 클래스 몸체에 정의해야됨. contructor에 정의 시 에러 발생
접근 가능성 |
public |
private |
클래스 내부 |
O |
O |
자식 클래스 내부 |
O |
X |
클래스 인스턴스를 통한 접근 |
O |
X |
class Person {
#name = '';
constructor(name){
this.#name = name;
}
getName() {
console.log(this.#name);
}
}
const p1 = new Person('dlwlrma');
p1.getName(); // dlwlrma
console.log(p1.#name); //SyntaxError: Private field '#name' must be declared in an enclosing class
static 필드 정의
- 최신 사양의 js에서는 정적 메서드와 마찬가지로 정적 필드를 정의 가능
class MyMath {
static PI = 22 / 7;
static #count = 0;
static increment() {
return ++MyMath.#count;
}
}
console.log(MyMath.PI); // 3.142857142857143
console.log(MyMath.increment()); // 1