class User {
constructor(name) {
this.name = name;
}
sayHi() {
alert(this.name);
}
}
// User가 함수라는 증거
alert(typeof User); // function
class User { ... }
문법 구조가 하는 일
User
라는 이름을 가진 함수를 만든다constructor
에서 가져온다sayHi
같은 Class 내에서 정의한 메서드를 User.prototype
에 저장한다new User
를 호출해 객체를 만들고 객체의 메서드를 호출하면 메서드를 prototype 프로퍼티를 통해 가져온다
이 과정이 있기 때문에 객체에서 Class 메서드에 접근할 수 있다
위의 설명을 코드로 표현한다면?
class User {
constructor(name) {
this.name = name;
}
sayHi() {
alert(this.name);
}
}
// Class는 함수이다
alert(typeof User); // function
// 정확히는 생성자 메서드와 동일하다
alert(User === User.prototype.constructor); // true
// Class 내부에서 정의한 메서드를 User.prototype에 저장된다
alert(User.prototype.sayHi); // alert(this.name);
// 현재 prototype 에는 메서드가 두 개 이다
alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi
class MyClass {
// 여러 메서드 정의 가능
constructor() {
...
}
method1() {
...
}
method2() {
...
}
method3() {
...
}
...
}
클래스는 위와 같은 기본 문법을 사용해 만들 수 있다
클래스를 만들고 new MyClass()
를 호출하면 내부에서 정의한 메서드가 들어있는 객체가 생성 된다
객체의 기본 상태를 설정해주는 생성자 메서드 constructor()
은 new
에 의해 자동으로 호출 되므로, 특별한 절차 없이 객체를 초기화 할 수 있다
ex)
class User {
constructor(name) {
this.name = name;
}
sayHi() {
alert(this.name);
}
}
// 사용법:
let user = new User("Minsu");
user.sayHi();
new User("Minsu")
를 호출하면 다음과 같은 일이 일어난다
1. 새로운 객체가 생성됨
2. 넘겨받은 인수와 함께 constructor
가 자동으로 실행된다. 이때 인수 "Minsu"
가 this.name
에 할당된다
이러한 과정을 거친 후에 user.sayHi()
같은 객체 메서드를 호출할 수 있다
메서드 사이에는 쉼표가 없다!
Class 메서드 사이에 쉼표를 넣게 되면 문법 에러가 발생한다.
Class와 관련된 표기법은 객체 리터럴 표기법과 차이가 있다. Class에서는 메서드 사이에 쉼표를 넣지 않아도 된다.
// class User 와 동일한 기능을 하는 순수 함수를 만들어보자
// 1. 생성자 함수를 만든다
function User(name) {
this.name = name;
}
// 모든 함수의 prototype은 'constructor' 프로퍼티를 기본으로 갖고 있기 때문에
// constructor 프로퍼티를 명시적으로 만들 필요가 없다
// 2. prototype에 메서드를 추가한다
User.prototype.sayHi = function() {
alert(this.name);
};
// 사용법
let user = new User("Minsu");
user.sayHi();
순수 함수로 Class 역할을 하는 함수를 선언하는 방법과 class
키워드를 사용하는 방법의 결과는 거의 같다
하지만 두 방법에는 중요한 차이가 몇 가지 있다
class
로 만든 함수에는 특수 내부 프로퍼티인 [[IsClassConstructor]]: true
가 이름표처럼 붙는다
[[IsClassConstructor]]: true
를 활용한다new
와 함께 호출하지 않으면 에러가 발생하는데 이 때 [[IsClassConstructor]]: true
가 사용된다class User {
constructor() {
}
alert(typeof User); // User의 타입은 함수이긴 하지만 그냥 호출할 수 없다
User(); // TypeError: Class constructor User cannot be invoked without 'new'
[[IsClassConstructor]]: true
가 사용된다class User {
constructor() {
}
}
alert(User); // class User { ... }
class 에 정의된 메서드는 열거할 수 없다 (non-enumerable)
prototype
프로퍼티에 추가된 메서드의 enumerable
플래그는 false
이다for..in
으로 객체를 순회할 때, 메서드는 순회 대상에서 제외하고자 하는 경우가 많다class는 항상 use strict
모드로 실행된다
use strict
모드가 적용된다constructor()
메서드는 Class 의 인스턴스 객체를 생성하고 초기화 하는 특별한 메서드 이다constructor() {
...
}
constructor(argument0) {
...
}
constructor(argument0, argument1) {
...
}
constructor(argument0, argument1, ... , argumentN) {
...
}
...
constructor
을 사용하면 다른 모든 메서드 호출보다 앞선 시점인, 인스턴스 객체를 초기화할 때 수행할 초기화 코드를 정의할 수 있다
class Person {
constructor(name) {
this.name = name;
}
introduct() {
console.log(`Hello, my name is ${this.name}`);
}
}
const otto = new Person('Otto');
otto.introduce();
Class에 생성자를 정의하지 않으면 기본 생성자를 사용한다
아무것도 상속하지 않는 기본 클래스 일 때의 기본 생성자는 빈 메서드 이다
constructor() {}
다른 클래스를 상속하는 경우, 기본 생성자는 자신의 매개변수를 부모 클래스의 생성자로 전달한다
constructor(...args) {
super(...args);
}
따라서 다음과 같은 코드를 작성할 수 있다
class ValidationError extends Error {
printCustomerMessage() {
return `Validation failed :-( (details: ${this.message})`;
}
}
try {
throw new ValidationError("Not a valid phone number");
} catch(error) {
if (error instanceof ValidationError) {
console.log(error.name); // ValidationError 가 아니라 Error!
console.log(error.printCustomerMessage());
} else {
console.log('Unknown error', error);'
throw error;
}
}
ValidationError
Class 는 아무런 초기화 동작도 필요하지 않으므로 생성자를 별도로 명시하지 않았으며 대신 기본 생성자가 매개변수로 부모 Error
Class의 초기화를 처리하고 있다
파생 Class에 직접 생성자를 정의할 경우, 부모 Class의 생성자를 호출하려면 직접 super()
를 호출해야 한다
"constructor"
라는 이름의 메서드는 하나의 Class에 오직 하나만 존재할 수 있다
두 개 이상의 constructor
메서드를 정의하면 SyntaxError 가 발생한다
https://ko.javascript.info/class
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/constructor