자바스크립트는 클래스가 필요없는 프로토타입 기반 객체지향 언어다
클래스 기반 언어에 익숙한 프로그래머를 위해 es6에서 클래스가 클래스 기반 객체지향 프로그래밍 언어와 흡사한 새로운 객체 생성 매커니즘을 제시
//생성자 함수
var Test = (function () {
function Test(x) {
this.x = x;
this.Hi = function () {
console.log('Hi' + this.x);
}
}
return Test;
})();
var test1 = new Test("생성자")
//클래스
class Test2 {
constructor(x){this.x=x}
Hi(){console.log('Hi'+this.x)}
}
const test2 = new Test2('클래스')
console.dir(test1)
console.dir(test2)
test1.Hi()
test2.Hi()
클래스와 생성자 함수 차이
| 구분 | 클래스 | 생성자 함수 |
|---|---|---|
| new | 없이 호출시 에러 | 없이 호출하면 일반함수로서 호출됨 |
| extends / super | 제공 (상속관계 구현을 더욱 간결하고 명료) | 지원 x |
| 호이스팅 | 발생하지 않는것처럼 동작 | |
| (함수와 다르게 TDZ(Temporal Dead Zone, 일시적 사각지대)가 존재하기 때문에 사용하기 전에 반드시 선언) | 함수 선언문으로 정의된 생성자함수 → 함수 호이스팅 | |
| 함수 표현식 정의 → 변수 호이스팅 | ||
| strict mode | 암묵적으로 지정되어 실행, 해제가능 | 암묵적으로 지정되지 않음 |
| constructor, 프로토타입 ,정적 메소드 | 모두 프로퍼티 어트리뷰트 [[Enumerable]]의 값이 false임 즉, 열거 되지 않음 | 존재 |
결론: 클래스를 흔히 프로토타입 기반 객체 생성 패턴의 단순한 문법적 설탕이라고 하는데, 저자는 새로운 객체 생성 메커니즘으로 본다.
class 키워드를 사용하여 정의
//익명 클래스 표현식
const Test = class {};
//기명 클래스 표현식
const Test = class MyClass {};
클래스는 일급 객체 (=즉 함수로 평가됨)
결론: 클래스는 일급객체여서 위의 특징이 활용됨.
결론: 클래스 선언문 이전에 일시적 사각지대(TDZ)에 빠지기 때문에 호이스팅이 발생하지 않는것처럼 동작한다.
따라서 선언전에 호출 x
결론: 클래스는 인스턴스를 생성하는 것이 유일한 존재 이유이므로 반드시 new 연산자와 함께 호출해야한다.
→ 에러발생
결론: 클래스 몸체 ({중괄호 안}) 에는 constructor, 프로토타입 메서드, 정적 메서드 등 세가지의 메서드만 선언할 수 있다. ⇒ 다른건 문법 에러남 최신문법에서는 필드, 인스턴스 프로퍼티 선언 가능
constructor는 인스턴스를 생성하고 초기화하기위한 특수한 메서드, 이름 변경 x
결론: constructor
class Test1 {
this.x= x; //문법 오류
}
class Test2 {
constructor(x) {
this.x = x;
}
}
그래서 사실 class 의 몸통은 두부분으로 나뉨 => 최신문법으로는 세부분
1.constructor: 인스턴스를 생성할 때 필요한 초기화 작업을 처리.
2. 메서드: 인스턴스가 수행할 수 있는 행동들을 정의.
3. 인스턴스 프로퍼티 (클래스 필드):
클래스 내부에서 this 없이 정의한 프로퍼티. 인스턴스가 생성될 때 자동으로 해당 프로퍼티가 추가
class Test2 {
constructor(x) {
this.x = x;
}
hi() {
console.log(this.x)
}
}
//만약 위에서 constructor가 없으면?
class Test2 {
// constructor가 없으므로 기본 생성자가 추가
hi() {
console.log(this.x); // this.x는 초기화되지 않아서 undefined일 수 있음
}
}
결론: 프로토타입 메서드와 정적 메서드는 클래스 내에서 사용하는 방식과 목적에 따라 차이남
프로토타입 메서드는 인스턴스를 통해 호출되는 메서드
정적메서드는 인스턴스를 생성하지 않아도 호출할 수 있는 메서드
결론: 인스턴스 프로퍼티는 constructor 내부에서 정의(public or private)
결론: 클래스 필드로 인해 자바스크립트도 자바의 클래스 정의방식 처럼 필드 를 사용할수 있게 됨.
자바스크립트는 기존에 클래스 몸체에 메서드만 선언할 수 있었으나, 최신 사양에서는 클래스 필드를 선언하고 private 필드와 static 필드를 사용할 수 있게 됨.
자바의 클래스 필드처럼 인스턴스 프로퍼티를 초기화 없이 선언할 수 있게 클래스 몸체에 직접 필드를 정의
class Test {
// 클래스 필드 정의 (인스턴스 프로퍼티)
name = '유선향';
constructor(age) {
this.age = age;
}
greet() {
console.log(`Hello, ${this.name}`);
}
}
class Counter {
// private static 필드 정의
static #count = 0;
constructor() {
Counter.#count++;
}
static getCount() {
return Counter.#count;
}
}
const counter1 = new Counter();
const counter2 = new Counter();
console.log(Counter.getCount()); // 2
console.log(Counter.#count); // SyntaxError: Private field '#count' must be declared in an enclosing class
class Counter {
// static 필드 정의 => 클래스의 모든 인스턴스가 공유
static count = 0;
constructor() {
Counter.count++;
}
static getCount() { // static 메서드 => 인스턴스 생성안해도 호출 가능
return Counter.count;
}
}
const counter1 = new Counter();
const counter2 = new Counter();
console.log(Counter.getCount()); // 2
결론: 클래스 상속이랑 생성자 함수 상속은 다름
상속을 통해 확장된 클래스 : 서브 클래스 , 파생 클래스, 자식 클래스
서브 클래스에게 상속된 클래스: 수퍼클래스, 베이스 클래스, 부모클래스
class Parent {
constructor(x) {
this.x = x;
}
hi() {
console.log(`잘잤니?`);
}
}
class Child extends Parent{
constructor(x, y) {
super(x);
this.y = y;
}
hi() {
super.hi(); //부모 클래스 메서드 호출
console.log(`안녕히 주무셨어요?`);
}
}
// 자식 클래스의 인스턴스 생성
const childInstance = new Child('x','y');
childInstance.hi(); //잘잤니? 안녕히 주무셨어요?
class Child extends Parent{
constructor(x, y) {
super(x); // 반드시 super()로 부모 클래스의 constructor 호출
this.y = y;
}
수퍼클래스와 서브클래스 모두 constructor 를 생략하면 빈객체가 생성된다
상속을 통한 클래스 인스턴스 생성 과정은 서브클래스와 수퍼클래스가 협력
서브클래스의 constructor가 super()를 호출함으로써 부모 클래스의 인스턴스를 생성하고,
이후 서브클래스에서 추가적인 초기화 작업을 수행
내부 메서드를 갖는 함수 객체로 평가 될 수 있는 모든 표현식을 사용할 수 있다.
자바스크립트의 빌트인 객체들(Array, String, Date 등)도 생성자 함수이기 때문에, extends를 사용하여 확장 가능
class MyArray extends Array {
uniq() {
return [...new Set(this)];
}
}
const arr = new MyArray(1, 2, 3, 3, 4);
console.log(arr.uniq()); // [1, 2, 3, 4]