ES6 클래스는 class 키워드를 사용하여 정의한다. 앞에서 살펴본 person 생성자 함수를 클래스로 정의해 보자.
클래스 이름은 생성자 함수와 마찬가지로 파스칼 케이스를 사용하는 것이 일반적이다. 파스칼 케이스를 사용하지 않아도 에러가 발생하지는 않는다.
// 클래스 선언문
class Person {
// constructor(생성자)
constructor(name) {
this._name = name;
}
sayHi() {
console.log(`Hi! ${this._name}`);
}
}
// 인스턴스 생성
const me = new Person('Lee');
me.sayHi(); // Hi! Lee
console.log(me instanceof Person); // true
클래스는 클래스 선언문 이전에 참조할 수 없다.
console.log(Foo);
// ReferenceError : Cannot accesee 'Foo' before initialization
class Foo{}
하지만 호이스팅이 발생하지 않는 것은 아니다. 클래스는 var 키워드로 선언한 변수처럼 호이스팅되지 않고 let, const 키워드로 선언한 변수처럼 호이스팅된다.따라서 클래스 선언문 이전에 일시적 사각지대에 빠지기 때문에 호이스팅이 발생하지 않는 것처럼 동작한다.
consst Foo = '';
{
// 호이스팅이 발생하지 않는다면 ''가 출력되어야 한다.
console.log(Foo);
// ReferenceError : Cannot access 'Foo' before initialization
class Foo{}
}
클래스 선언문도 변수 선언, 함수 정의와 마찬가지로 호이스팅이 발생한다. 호이스팅은 var, let, const, function, class 키워드를 사용한 모든 선언문에 적용된다. 다시 말해, 선언문을 통해 모든 식별자는 호이스팅된다. 모든 선언문은 런타임 이전에 먼저 실행되기 때문이다.
일반적이지는 않지만, 표현식으로도 클래스를 정의할 수 있다. 함수와 마찬가지로 클래스는 이름을 가질 수도 갖지 않을 수도 있다. 이때 클래스가 할당된 변수를 사용해 클래스를 생성하지 않고 기명 클래스의 클래스 이름을 사용해 클래스를 생성하면 에러가 발생한다. 이는 함수와 마찬가지로 클래스 표현식에서 사용한 클래스 이름은 외부 코드에서 접근 불가능하기 때문이다.
// 클래스명 MyClass는 함수 표현식과 동일하게 클래스 몸체 내부에서만 유효한 식별자이다.
const Foo = class MyClass{};
const foo = new Foo();
console.log(foo); // MyClass {}
new MyClass(): // ReferenceError : MyClass is not defined
마치 생성자 함수와 같이 new 연산자와 함께 클래스 이름을 호출하면 클래스의 인스턴스가 생성된다.
class Foo{};
const foo = new Foo();
위 코드에서 new 연산자와 함께 호출한 Foo는 클래스의 이름이 아니라, constructor
이다. 표현식이 아닌 선언식으로 정의한 클래스의 이름은 constructor
와 동일하다
// Foo는 사실 생성자 함수(constructor)이다.
console.log(Object.getPrototype(foo).constructor === Foo); // true
new 연산자를 사용하지 않고 constructor를 호출하면 TypeError
가 발생한다. constructor
는 new
연산자 없이 호출 가능하다
class Foo {};
const foo = Foo(); // TypeError: class constructor Foo cannot invoked without "new"
constructor
는 인스턴스를 생성하고 클래스 필드를 초기화하기 위한 특수한 메소드이다.
// 클래스 선언문
class Person {
// constructor(생성자). 이름을 바꿀 수 없다.
constructor(name) {
// this는 클래스가 생성할 인스턴스를 가리킨다.
// _name은 클래스 필드이다.
this._name = name;
}
}
// 인스턴스 생성
const me = new Person('Lee');
console.log(me); // Person {_name: "Lee"}
constructor
는 클래스 내에 한 개만 존재할 수 있으며 만약 클래스가 2개 이상의 constructor를 포함하면 문법 에러(SyntaxError)가 발생한다. 인스턴스를 생성할 때 new 연산자와 함께 호출한 것이 바로 constructor이며 constructor의 파라미터에 전달한 값은 클래스 필드에 할당한다.
constructor
는 생략할 수 있다. constructor를 생략하면 클래스에 constructor() {}
를 포함한 것과 동일하게 동작한다. 즉, 빈 객체를 생성한다. 따라서 인스턴스에 프로퍼티를 추가하려면 인스턴스를 생성한 이후, 프로퍼티를 동적으로 추가해야 한다.
class Foo { }
const foo = new Foo();
console.log(foo); // Foo {}
// 프로퍼티 동적 할당 및 초기화
foo.num = 1;
console.log(foo); // Foo { num: 1 }
constructor
는 인스턴스의 생성과 동시에 클래스 필드의 생성과 초기화를 실행한다. 따라서 클래스 필드를 초기화해야 한다면 constructor를 생략해서는 안된다.
class Foo {
// constructor는 인스턴스의 생성과 동시에 클래스 필드의 생성과 초기화를 실행한다.
constructor(num) {
this.num = num;
}
}
const foo = new Foo(1);
console.log(foo); // Foo { num: 1 }