이번 시간에는 지난 시간에 생성자 함수를 만든 것에 이어 상속에 대해 설명하겠습니다.
상속
상속은 부모 생성자의 기능을 물려받으면서 새로운 기능도 추가하는 것을 의미합니다. 외국에서는 상속 대신 확장(extend)이라는 말을 쓴다고 했죠? 사실 확장이 더 어울리기도 하고요. 어쨌든, 다음의 코드를 보시죠.
function Vehicle(name, speed) {
this.name = name;
this.speed = speed;
}
Vehicle.prototype.drive = function () {
console.log(this.name + ' runs at ' + this.speed)
};
var tico = new Vehicle('tico', 50);
tico.drive(); // 'tico runs at 50'
function Sedan(name, speed, maxSpeed) {
Vehicle.apply(this, arguments)
this.maxSpeed = maxSpeed;
}
Sedan.prototype = Object.create(Vehicle.prototype);
Sedan.prototype.constructor = Sedan;
Sedan.prototype.boost = function () {
console.log(this.name + ' boosts its speed at ' + this.maxSpeed);
};
var sonata = new Sedan('sonata', 100, 200);
sonata.drive(); // 'sonata runs at 100'
sonata.boost(); // 'sonata boosts its speed at 200'
처음보는 분들은 대혼란에 빠질 만한 코드네요. 사실 위의 코드가 모든 사람들이 쓰는 코드는 아닙니다. 상속하는 수 많은 방법이 있는데 에러가 거의 없는 방법 중 하나입니다. 보시면 Vehicle 생성자와 prototype에 메소드를 넣는 것까지는 아실 겁니다. 지난 시간의 코드를 그대로 썼습니다. tico라는 Vehicle도 만들었고요. 그 후에는 Sedan이라는 Vehicle을 상속하는 생성자를 만들었습니다.
그 다음에 나오는 Vehicle.apply(this, arguments);
는 Vehicle의 this들을 그대로 받으란 뜻입니다. apply라는 함수는 이름 그대로 적용하는 메소드입니다. 즉 해석하면 Vehicle 생성자에 this와 arguments를 적용하라는 코드죠? arguments는 매개변수를 의미합니다. Sedan은 매개변수로 name과 speed, maxSpeed가 있죠? 이게 그대로 Vehicle과 연결됩니다. 다만, maxSpeed는 Vehicle이 갖고 있지 않기 때문에 무시되고요. 그 후에 이제 Sedan만 갖고 있는 maxSpeed 속성을 따로 추가한거죠. 이렇게 Vehicle의 속성을 상속(또는 확장)받았고, 이제 메소드를 처리하는 부분입니다.
생성자 아래의 Sedan.prototype = Object.create(Vehicle.prototype);
은 Sedan의 prototype과 Vehicle의 prototype을 연결하는 겁니다. 그래야 Vehicle의 메소드였던 drive를 쓸 수 있겠죠? Object.create
는 Vehicle.prototype
을 상속하는 새로운 객체를 만드는 메소드입니다. 그 상속한 객체를 Sedan.prototype
에 대입하니까 Sedan이 Vehicle을 상속하게 되는 거죠.
여기서 Object.create(Vehicle.prototype)
과 new Vehicle()
의 차이를 알아두시면 좋습니다. Object.create는 객체를 만들되 생성자는 실행하지 않는 겁니다. 즉 그냥 프로토타입만 넣는거죠.
참고로 Sedan.prototype.constructor = Sedan;
은 오류를 수정하는 코드입니다. 전 시간에 생성자.prototype.constructor === 생성자
여야한다는 말을 드렸었죠? 생성자의 부모의 자식을 찾아라 하면 당연히 원래 생성자가 나와야겠죠. 하지만, 이 줄을 빼고 제가 한 방법대로 상속을 하면 Sedan.prototype.constructor === Vehicle
이 됩니다. 이건 어쩔 수 없는 자바스크립트의 문제입니다. 그래서 이것을 고치기 위해 Sedan.prototype.constructor
에 Sedan을 다시 넣어주는 겁니다. 다른 상속 방법이 더 자신에게 맞고 그에 따른 문제점은 적절히 처리할 수 있다면 그 방법을 쓰시면 됩니다.
그 다음에 Sedan.prototype.boost
로 boost라는 메소드를 Sedan에 만들었습니다. 이제 Sedan은 Vehicle에게 상속받은 drive와 Vehicle 생성자를 확장한 자신의 boost 메소드를 쓸 수 있습니다!
내친김에 Truck 생성자도 만들어보죠. boost 대신에 load라는 짐을 싣는 메소드를 만들어봅시다.
function Truck(name, speed, capacity) {
Vehicle.apply(this, arguments);
this.capacity = capacity;
}
Truck.prototype = Object.create(Vehicle.prototype);
Truck.prototype.constructor = Truck;
Truck.prototype.load = function (weight) {
if (weight > this.capacity) {
return console.error('아이고 무거워!');
}
return console.log('짐을 실었습니다!');
};
var boongboong = new Truck('boongboong', 40, 100);
boongboong.drive(); // 'boongboong runs at 40'
boongboong.load(120); // '아이고 무거워!'
capacity는 적재량입니다. load 메소드를 보면, 적재량보다 무거운 짐을 실으면 무겁다고 메시지가 뜨죠?
다음 시간에는 지금까지 배운 것을 활용해서 게임을 또 만들어봅시다. 사실 게임이야말로 가장 어려운 프로그래밍입니다. 자바스크립트에 대해 더 알아가면서 점점 진화하는 게임을 만들어보죠! 이제는 콘솔은 졸업하고 화면에 직접 표시해봅시다.
function Person(name, color, height, age) {
this.color = color;
this.name = name;
this.height = height;
this.age = age;
}
Person.prototype.blackPerson = function () {
console.log("농구")
}
Person.prototype.yellowPerson = function () {
if(this.color === 'yellow') {
console.log("태권도")
} else {
console.log('다른 인종을 선택해 보세요.')
}
}
Person.prototype.whitePerson = function () {
console.log("펜싱");
}
Person.prototype.attack = function() {
console.log('공격')
}
const jeffrey = new Person('jeffrey', 'yellow', 175, 20);
jeffrey.yellowPerson();
function Anmal(legs) {
Person.apply(this, arguments); //여기서 name, height만
this.legs = legs;
}
const tiger = new Anmal('tiger', 200, 4);
console.log("tiger", tiger);
Animal.prototype = Object.create(Person.prototype); //attack 함수만 필요
Animal.prototype.constructor = Animal;
const tiger = new Animal('tiger', 200, 4);
console.log("tiger", tiger);
주석에 말한거처럼 상속을 this.name, this.height만 필요하고
저기서 function도 attack이라는 function만 필요하거든요
하지만 제 생각에는 Person.apply(this.name, this.height, arguments)
이런식과
Animal.prototype = Object.create(Person.prototype.attack)
이런식으로하면
attack함수랑 this.name, this.height를 부를수있을거같은데 안되네요.