7 클래스
클래스
음식 > 과일 > 포도 > 샤인머스캣
음식, 과일, 포도는 추상적인 개념 : 클래스
샤인머스캣은 클래스의 속성을 지니면서 실존한다. (먹을 수 있다) : 인스턴스
자바스크립트와 클래스
자바스크립트는 프로토타입 언어라 클래스 개념이 존재하지는 않지만, 클래스와 비슷한 관점에서 해석해 볼 수는 있다.
인스턴스에 상속되는 메서드를 인스턴스 메서드, 인스턴스에 상속되지 않는 메서드를 스태틱 메서드라고 한다. 자바스크립트 진영에서는 인스턴스 메서드를 프로토타입 메서드라고 더 많이 부른다.
var Person = function (name) {
this.name = name;
}
// 프로토타입 메서드
Person.prototype.getName = function () {
return this.name;
}
// 스태틱 메서드
Person.sayHello = function () {
console.log("안녕!");
}클래스 상속
가볍게 읽자! ES6에 도입된 클래스 문법을 사용하면 클래스 정의와 상속을 간단히 할 수 있다.
프로토타입 체인을 이용해서 전통적인 클래스 상속을 흉내 낼 수 있다. (완벽하진 않다) 자바스크립트에는 클래스 개념이 없다. ES6에서 클래스 개념이 도입되긴 했지만, 그것 역시 prototype을 이용한 것이다. 자바스크립트에서 클래스 상속을 구현했다는 것은 프로토타입 체인을 잘 연결했다는 것으로 생각하면 된다.
var Grade = function () {
var args = Array.prototype.slice.call(arguments);
for (var i = 0; i < args.length; i++) {
this[i] = args[i];
}
this.length = args.length;
}
Grade.prototype = []; // 배열의 인스턴스를 프로토타입에 연결
var g = new Grade(100, 80);
g.push(90);
console.log(g); // Grade {0: 100, 1: 80, 2: 90, length: 3}6장의 프로토타입 체인에서 봤던 코드. Array를 상속한 Grade라고 해석할 수 있지만 세부적으로 봤을 때 문제가 있다.
length 프로퍼티가 삭제 가능
length 프로퍼티는 Grade의 프로퍼티로 존재함. Array의 length는 configurable이 false라 삭제할 수 없지만 Grade의 length 프로퍼티는 삭제할 수 있다.
Grade.prototype이 빈 배열을 참조
length 프로퍼티가 삭제된 상태에서 다시 length를 참조하는 작업을 하면, 자바스크립트 엔진은
__proto__를 타고 Array.prototype.length에 접근한다. 빈 배열을 참조하고 있었기 때문에 length는 0일 것이고, 실제 Grade의 내용과는 관계없이 length가 설정된다.g의 constructor가 Array를 가리키고 있다.
g.constructor를 호출하면 프로토타입 체이닝을 따라서
g.__proto__.__proto__의 constructor, Array를 갖게 된다. g는 Grade의 인스턴스이기 때문에 constructor 로도 Grade를 갖는 것이 더 적절할 것이다.
클래스는 틀이다. 따라서 클래스에 있는 값이 인스턴스의 동작에 영향을 줘서는 안 된다. 따라서 상속 개념을 잘 흉내 내려면 클래스가 구체적인 데이터를 지니지 않게 해야 한다. 클래스가 구체적인 데이터를 지니지 않게 하는 방법은 2가지가 있다.
일일이 지워주기 :
subclass.prototype에 접근해서 모든 프로퍼티를 delete로 제거하면 된다.Bridge 생성자 함수 활용하기 : subclass.prototype에 직접 superclass의 인스턴스를 할당하는 대신 빈 생성자 함수 Bridge 인스턴스를 연결하고, Bridge.prototype에 superclass.prototype을 연결하는 방식이다.
Object.create를 이용하는 방법
// 생략 Square.prototype = Object.create(Rectangle.prototype);이렇게 하면 subclass의 prototype의
__proto__가 superclass의 prototype을 바라보지만, superclass의 인스턴스가 되지는 않기 때문에 앞선 두 방법보다는 간단하고 안전하다.
추가로 constructor를 복구하는 방법 역시 필요하다. (원래의 subclass를 바라보도록)
욕심을 내면 super 또한 apply를 이용해서 구현할 수 있다.
클래스 문법
기본 문법
var Person = class {
constructor (name) {
this.name = name;
}
static sayHello () {
console.log("안녕!");
}
introduce() {
console.log(this.name + "입니다!")
}
}상속
var player = class extends Person {
constructor(name, backNumber) {
super(name);
this.backNumber = backNumber
}
}