자바스크립트는 프로토타입을 기반으로 한 강력한 객체지향 프로그래밍 능력을 지니고 있다.
프로토타입 기반 객체지향 언어는 클래스가 필요 없는 객체지향 프로그래밍 언어지만, 이는 자바스크립트를 어렵게 느끼게 만드는 하나의 장벽처럼 인식되었다.
그렇다고 ES6에서 클래스를 지원하는 것이 기존의 프로토타입 기반 객체지향 모델을 폐지하고 새로운 객체지향 모델을 제공하는 것은 아니다.
클래스는 생성자 함수와 매우 유사하게 동작하지만 몇 가지 차이가 있다.
클래스는 생성자 함수 기반의 객체 생성 방식보다 견고하고 명료하다.
특히 클래스의 extends와 super 키워드는 상속 관계 구현을 더욱 간결하고 명료하게 한다.
하지만 클래스가 기존의 생성자 함수를 통한 객체 생성방식보다 우월한 것은 아니기에, 클래스는 새로운 객체 생성 매커니즘으로 보는 것이 좀 더 합당하다.
클래스 몸체에는 0개 이상의 메서드만 정의할 수 있다.
클래스 몸체에서 정의할 수 있는 메서드는 constructor(생성자),프로토타입 메서드, 정적 메서드 3가지다.
// 생성자 함수
var Person = (function () {
//생성자 함수
function Person(name) {
this.name = name;
}
// 프로토타입 메서드
Person.prototype.sayHi = function() {
console.log('Hi! My Name is ' + this. name);
};
//정적 메서드
Person.sayHello = function () {
console.log('hello');
};
return Person;
}());
// 클래스
class Person {
// 생성자
constructor(name){
this.name = name;
}
// 프로토타입 메서드
sayHi() {
console.log(`Hi! My name is ${this.name}`)
}
// 정적 메서드
static sayHello() {
console.log('Hello');
}
}
클래스 선언문으로 정의한 클래스는 함수 선언문과 같이 소스코드 평가 과정, 즉 런타임 이전에 먼저 평가되어 함수 객체를 생성한다. 이때 클래스가 평가되어 생성된 함수 객체는 생성자 함수로서 호출할 수 있는 함수, 즉 constructor다.
생성자 함수로서 호출할 수 있는 함수는 함수 정의가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 더불어 생성된다.
프로토타입과 생성자 함수는 단독으로 존재할 수 없고 언제나 쌍으로 존재하기 때문이다.
단 클래스는 클래스 정의 이전에 참조할 수 없다.
클래스 선언문도 호이스팅이 발생하지만, let,const 키워드로 선언한 변수처럼 호이스팅 되기에 일시적 사각지대(TDZ)에 빠지기 때문에 호이스팅이 발생하지 않는 것처럼 동작한다.
클래스는 생성자 함수이며 new 연산자와 함꼐 호출되어 인스턴스를 생성한다.
클래스 몸체에는 0개 이상의 메서드만 선언할 수 있다.
메서드는 constructor(생서자),프로토타입 메서드, 정적 메서드 3가지가 있다.
클래스는 평가되어 함수 객체가 된다.
클래스도 함수 객체 고유의 프로퍼티를 모두 갖고 있다.
함수와 동일하게 프로토타입과 연결되어 있으며 자신의 스코프체인을 구성한다.
prototype 프로퍼티가 가리키는 프로토타입 객체의 constructor 프로퍼티는
클래스 자신을 가리키고 있다.
이는 클래스가 인스턴슬르 생성하는 생성자함수라는 것을 의미한다.
클래스가 생성한 인스턴스를 생성하고, constructor 내부를 살펴보면 this는 클래스가 생성한 인스턴스를 가리킨다.
흥미로운 점은, 클래스가 평가되어 생성된 함수 객체는 클래스가 생성한 인스턴스 어디에도 constructor 메서드가 보이지 않는다는 것이다.
constructor는 메서드로 평가되는 것이 아니라, 클래스가 평가되어 생성한 함수 객체 코드의 일부가 된다. 다시 말해, 클래스 정의가 평가되면, constructor의 기술된 동작을 하는 함수 객체가 생성된다.
클래스의 constructor 메서드와 프로토타입의 constructor 프로퍼티는 이름이 같아 혼동하기 쉽지만 직접적인 관련은 없다.
class 내부에서 constructor는 생략할 수 있지만, 빈 constructor가 암묵적으로 정의되며 빈 constructor에 의해 빈 객체를 생성한다.
프로퍼티가 추가되어 초기화 된 인스턴스를 생성하려면 constructor 내부에서 this에 인스턴스 프로퍼티를 추가한다.
class Person {
constructor() {
// 고정값으로 인스턴스 초기화
this.name = 'Lee';
this.address = 'Seoul';
}
}
// 인스턴스 프로퍼티가 추가된다.
const me = new Person();
console.log(me); // Person { name: 'Lee', address:'Seoul' }
인스턴스를 생성할 때 클래스 외부에서 인스턴스 프로퍼티의 초기값을 전달하려면
constructor에 매개변수를 선언하고, 인스턴스를 생성할 때 초기값을 전달하여 constructor의 매개변수에 전달할 수 있다.
class Person {
constructor(name,address) {
// 고정값으로 인스턴스 초기화
this.name = name;
this.address = address;
}
}
// 인스턴스 프로퍼티가 추가된다.
const me = new Person('Lee','Seoul');
console.log(me); // Person { name: 'Lee', address:'Seoul' }
이처럼 constructor 내에서는 인스턴스의 생성과 동시에 인스턴스 프로퍼티 추가를 통해 인스턴스의 초기화를 실행한다.
따라서 인스턴스의 초기화가 필요하다면 constructor를 생략해서는 안된다.
또한 constructor는 별도의 반환문을 갖지 않아야한다.
만약 this가 아닌 다른 객체를 명시적으로 반환하면 this, 즉 인스턴스가 반환되지 못하고 return문에 명시된 객체가 반환된다.
클래스 몸체에서 정의한 세머드는 인스턴스의 프로토타입에 존재하는 프로터티입 메서드가 된다. 인스턴스는 프로토타입 메서드를 상속받아 사용할 수 있다.
정적 프로퍼티/ 메서드에서 살펴보았듯이 정적 메서드는 인스턴스를 생성하지 않아도 호출할 수 있는 메서드를 말한다.
클래스에서는 static 키워드를 붙이면 정적 메서드가 된다.
정적 메서드는 클래스에 바인딩 된 메서드로서 인수턴스를 생성하지 않아도 호출할 수 있다.
클래스 몸체에서 정의할 수 있는 메서드는 constructor(생성자),프로토타입 메서드, 정적 메서드 3가지다
클래스 선언문도 호이스팅이 발생하지만, let,const 키워드로 선언한 변수처럼 호이스팅 되기에 일시적 사각지대(TDZ)에 빠지기 때문에 호이스팅이 발생하지 않는 것처럼 동작한다.
constructor는 메서드로 평가되는 것이 아니라, 클래스가 평가되어 생성한 함수 객체 코드의 일부가 된다. 다시 말해, 클래스 정의가 평가되면, constructor의 기술된 동작을 하는 함수 객체가 생성된다.
인스턴스를 생성할 때 클래스 외부에서 인스턴스 프로퍼티의 초기값을 전달하려면
constructor에 매개변수를 선언하고, 인스턴스를 생성할 때 초기값을 전달하여 constructor의 매개변수에 전달할 수 있다.
클래스 몸체에서 정의한 세머드는 인스턴스의 프로토타입에 존재하는 프로터티입 메서드가 된다. 인스턴스는 프로토타입 메서드를 상속받아 사용할 수 있다.
정적 프로퍼티/ 메서드에서 살펴보았듯이 정적 메서드는 인스턴스를 생성하지 않아도 호출할 수 있는 메서드를 말한다.
클래스에서는 static 키워드를 붙이면 정적 메서드가 된다.
정적 메서드는 클래스에 바인딩 된 메서드로서 인수턴스를 생성하지 않아도 호출할 수 있다.