안녕하세요. 이번 시간에는 클래스(class)에 대해 알아보겠습니다.
그 동안 자바스크립트에 클래스가 없었습니다. 그래서 다른 언어를 하셨던 분들은 자바스크립트의 객체에 대해 헷갈려했습니다. 하지만 이제 자바스크립트도 클래스가 있습니다! (하지만 내부적으로는 그대로 프로토타입을 따릅니다)
var Human = function(type) {
this.type = type || 'human';
};
Human.isHuman = function(human) {
return human instanceof Human;
}
Human.prototype.breathe = function() {
alert('h-a-a-a-m');
};
var Zero = function(type, firstName, lastName) {
Human.apply(this, arguments);
this.firstName = firstName;
this.lastName = lastName;
};
Zero.prototype = Object.create(Human.prototype);
Zero.prototype.constructor = Zero; // 상속하는 부분
Zero.prototype.sayName = function() {
alert(this.firstName + ' ' + this.lastName);
};
var oldZero = new Zero('human', 'Zero', 'Cho');
Human.isHuman(oldZero); // true
간단히 보면 Human 객체를 Zero 객체가 상속받고 있습니다. Human 생성자에는 isHuman이라는 static 메소드도 있네요. breathe는 모든 Human 객체가 받는 메소드이고요. ES6에서는 놀랍게 바뀝니다.
class Human {
constructor(type = 'human') {
this.type = type;
}
static isHuman(human) {
return human instanceof Human;
}
breathe() {
alert('h-a-a-a-m');
}
}
class Zero extends Human {
constructor(type, firstName, lastName) {
super(type);
this.firstName = firstName;
this.lastName = lastName;
}
sayName() {
super.breathe();
alert(`${this.firstName} ${this.lastName}`);
}
}
const newZero = new Zero('human', 'Zero', 'Cho');
Human.isHuman(newZero); // true
혼잡했던 생성자와 상속 코드가 깔끔해졌습니다. 물론 새로운 기능이 추가된 것은 아니지만 눈이 즐거워졌죠. 실수할 일도 줄어들고요. 실제로 이렇게 클래스로 만들어둔 것은 new를 붙이지 않으면 에러가 발생합니다. 다들 생성자에 new를 붙이지 않아서 window를 수정했던 경험이 있으실 겁니다. 이제는 그럴 일이 없습니다. 원천 차단되었거든요.
이전에 function Object() {}
로 만들던 생성자 객체를 이제 class로 만들 수 있습니다. 그리고 복잡했던 상속을 class 이름 extends 부모 {}로 간단하게 처리할 수 있게 되었죠.
constructor 함수는 객체가 생성되었을 때 실행되는 함수입니다. constructor의 매개변수들은 new Zero(인자)
객체로 호출할 때 사용하는 인자들을 처리하고 있습니다. super은 아래에서 설명드리겠습니다.
객체의 prototype에 정의했던 메소드들도 이제 class 안에 넣으면 됩니다. 자연스럽죠?
Human.isHuman같은 객체의 static 메소드도 간명하게 표시할 수 있게 되었습니다. static 이름() {}
처럼 앞에 static만 붙여주면 됩니다.
주목할 점은 super
입니다. 부모 객체에 접근하는 방법인데요. constructor 안과 sayName 함수 안에서 두 번 발견할 수 있습니다. constructor 안의 super은 부모의 생성자에 type을 전달하는 역할을 합니다. 부모 객체에 없는 firstName과 lastName은 따로 처리해주어야 합니다.
sayName 안의 super 역시 부모 객체에 접근하여 메소드를 호출하는 겁니다. 부모 객체의 메소드를 재사용하고 싶을 때 주로 사용합니다. 위의 예시에서는 newZero.sayName()
할 경우 Human.prototype.breathe()
가 호출된 후 alert가 발생합니다.
참고로 class의 body는 strict 모드가 기본 적용됩니다. 아래의 경우 window가 나와야할 것 같지만, undefined가 나옵니다. say 메서드 내부는 strict 모드가 적용되기 때문입니다. 애초에 왜 window랑 undefined가 나오는지 이해가 안 된다면 this 강좌 보고 오셔야 합니다.
class obj {
say() {
console.log(this);
}
}
obj2 = new obj();
obj3 = obj2.say;
obj3();
다음 시간에는 객체 해체에 대해 알아보겠습니다. 객체를 해체한다니, 뭔가 있을거 같죠?
그렇지 않다면 클래스의 장점을 이길만한 프로토타입 방식의 상속이 장점이 있을까요?