자바스크립트는 프로토타입 기반 객체지향 언어라 클래스가 필요없다.
자바스크립트 클래스는 함수이며 프로토타입 기반 패턴은 클래스 기반 패턴처럼 사용할 수 있도록 하는 syntatic sugar다.
클래스도 함수이기 때문에 일급 객체다.
클래스 정의는 클래스 선언문, 클래스 표현식(익명, 기명 클래스 표현식)으로 정의 가능하다.
클래스 선언문으로 클래스를 정의하면, 소스 코드 평가 과정에 먼저 실행되어 함수 객체를 생성한다.
생성된 함수 객체는 constructor라서 함수 객체가 생성되는 시점에 프로토타입도 같이 생성된다.
따라서 생성자 함수처럼 호이스팅이 발생하지만, 클래스는 클래스 정의 이전에 참조할 수 없다.
클래스는 생성자 함수이며 new
연산자와 함께 호출되어 인스턴스를 생성한다.
생성자 함수와 달리 반드시 new
와 함께 호출되어야 한다.
new
연산자와 함께 호출되지 않으면 에러가 발생한다.
클래스도 함수와 마찬가지로 식별자로 호출한다.(기명 함수 표현식으로 정의된 함수를 식별자에 할당하는 경우를 생각하면 된다.)
클래스 몸체에서 정의할 수 있는 메서드는 생성자, 프로토타입 메서드, 인스턴스 메서드, 정적 메서드다.
인스턴스를 생성하고 초기화하는 특수한 메서드다.
constructor
내부에서 this
에 추가한 프로퍼티는 클래스가 생성할 인스턴스의 프로퍼티가 된다.
주의해야 할 점
constructor
는 하나의 클래스에 하나만 존재한다.constructor
를 작성하지 않으면 암묵적으로 빈 constructor
가 정의된다.constructor
내부에서 별도의 반환문을 쓰면 안된다.(생성자 함수에서의 return문과 똑같이 작동)클래스 몸체에 정의한 메서드다.
클래스 몸체에 정의한 메서드는 인스턴스의 프로토타입에 존재하는 프로토타입 메서드가 된다.
인스턴스를 생성하지 않아도 호출할 수 있는 메서드다
static
키워드를 붙여 클래스 몸체에 메서드를 정의하면 정적 메서드가 된다.
이는 클래스가 평가되어 생성되는 함수 객체의 메서드가 된다.
정적 메서드는 인스턴스를 통해 호출할 수 없다.
표준 빌트인 객체 Math, Number, JSON, Object, Reflect
등은 다양한 정적 메서드를 가지고 있으며, 이 정적 메서드들은 애플리케이션 전역에서 사용할 수 있는 유틸리티 함수다.
static 키워드를 쓰는 이유 중 하나는 정적 패토리 메서드 패턴을 사용할 수 있기 때문입니다.
class IdolModel{
name;
year;
constructor(name, year){
this.name = name;
this.year = year;
}
static fromObject(object){
return new IdolModel(
object.name,
object.year,
);
}
static fromList(list){
return new IdolModel(
list[0],
list[1],
);
}
}
생성자 대신 사용할 수 있습니다. 특정 데이터로부터 인스턴스를 생성할 수 있도록 템플릿화 할 수 있는 장점이 있습니다.
const yuJin2 = IdolModel.fromObject({
name: '안유진',
year: 2003,
});
console.log(yuJin2); // IdolModel {name: '안유진', year: 2003}
const wonYoung = IdolModel.fromList(
[
'장원영',
2003,
]
);
console.log(wonYoung); // IdolModel {name: '장원영', year: 2003}
for...in
문이나 Object.keys
메서드 등으로 열거할 수 없다.(프로퍼티 어트리뷰트 [[Enumerable]]
이 false다.인스턴스 프로퍼티는 constructor
내부에서 정의하여 초기화한다.
클래스 필드 정의로 constructor
밖에서도 정의할 수 있다.
클래스에서도 접근자 프로퍼티 getter
, setter
를 정의할 수 있다.
setter
는 단 하나의 값만 할당받기 때문에 단 하나의 매개변수만 선언할 수 있다.
클래스 기반 객체지향 언어의 클래스 필드처럼 인스턴스 변수를 정의할 수 있다.
함수는 일급 객체이므로 함수를 클래스 필드에 할당할 수 있다. 클래스 필드에 메서드를 할당하면 인스턴스 메서드가 된다.(권장하지 않음)
#
을 클래스 필드와 함께 사용해서 private 필드를 정의할 수 있다.
private 필드는 접근자 프로퍼티를 통해서 접근 가능하다.
static 메서드와 마찬가지로 static 키워드를 사용해 정적 필드를 정의할 수 있다.
상속에 의한 클래스 확장은 프로토타입 기반 상속과는 다른 개념이다.
프로토타입 기반 상속은 프로토타입 체인을 통해 프로퍼티와 메서드를 상속한다.
상속에 의한 클래스 확장은 기존 클래스를 상속받아 새로운 클래스를 확장한다.
extends
키워드를 사용하여 상속을 통한 클래스 확장이 가능하다.
수퍼클래스와 서브클래스는 인스턴스의 프로토타입 체인 뿐만 아니라 클래스 간의 프로토타입 체인도 생성한다.
이를 통해 프로토타입 메서드, 정적 메서드 모두 상속이 가능하다.
또한 클래스는 생성자 함수를 상속할 수도 있다.
extends
키워드 다음에는 [[Construct]] 내부 메서드를 갖는 함수 객체로 평가될 수 있는 모든 표현식을 사용할 수 있다. 이를 활요하여 동적으로 상속할 대상을 결정할 수도 있다.
서브클래스에서 constructor를 생략하면 다음과 같은 constructor가 암묵적으로 정의된다.
constructor(...args) {
super(...args);
}
constructor
를 호출한다.서브클래스에서 constructor를 생략하지 않는 경우 반드시 super()
를 호출해야한다.
super
를 호출하기 전에는 this
를 참조할 수 없다.
메서드 내에서 super를 참조하면 수퍼클래스의 메서드를 호출할 수 있다.
메서드는 내부 슬롯 [[HomeObject]]를 가지고, 자신을 바인딩하고 있는 객체를 가리킨다.
[[HomeObject]]는 오직 ES6 메서드 축약 표현으로 정의된 함수만 갖는다.
[[HomeObject]]를 가지는 함수만 super 참조가 가능하기 때문에 ES6 메서드만 super 참조가 가능하다.
서브클래스의 정적 메서드 내에서 super 참조를 통한 메서드 호출은 수퍼클래스의 정적 메서드를 호출한다.
자바스크립트 엔진이 클래스를 평가할 때 수퍼클래스인지 서브클래스인지 구분하기 위해 내부 슬롯 [[ConstructorKind]]를 확인한다.
[[ConstructorKind]] 내부슬롯은 상속클래스면 "derived"를 상속 클래스가 아니라면 "base"를 값으로 갖는다.
new
연산자와 함께 호출했을 때 [[ConstructorKind]] 값을 확인해서 수퍼클래스와 서브클래스의 호출이 구분된다.
서브클래스는 자신이 직접 인스턴스를 생성하지 않고 수퍼클래스에게 인스턴스 생성을 위임한다. 그렇기 때문에 반드시 서브클래스에서 super
를 호출해야 한다.
this
바인딩암묵적으로 인스턴스를 생성하는 것은 수퍼클래스지만 new
연산자와 함께 호출된 클래스는 서브클래스다.
즉, new.target
은 서브클래스를 가리키기 때문에 암묵적으로 생성된 인스턴스는 서브클래스가 생성한 것으로 처리된다.(this
가 서브클래스의 인스턴스임)
수퍼클래스의 인스턴스 초기화
서브클래스 constructor로 복귀 및 this
바인딩
super가 반환한 인스턴스가 this
에 바인딩된다. 서브클래스는 별도의 인스턴스를 생성하지 않고 super가 반환한 인스턴스를 this
에 바인딩하여 그대로 사용한다.
서브클래스의 인스턴스 초기화
인스턴스 반환
extends
키워드 뒤에 올 수 있는 것은 클래스 뿐만 아니라 constructor인 함수 객체로 평가될 수 있는 모든 표현식을 사용할 수 있다.
따라서 String, Number, Array 같은 표준 빌트인 객체도 extends
키워드 뒤에 사용할 수 있다.