게시글

5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭
강좌17 - JavaScript - 8년 전 등록 / 7년 전 수정

객체 상속

이번 시간에는 지난 시간에 생성자 함수를 만든 것에 이어 상속에 대해 설명하겠습니다. 

상속

상속은 부모 생성자의 기능을 물려받으면서 새로운 기능도 추가하는 것을 의미합니다. 외국에서는 상속 대신 확장(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.createVehicle.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 메소드를 보면, 적재량보다 무거운 짐을 실으면 무겁다고 메시지가 뜨죠?

다음 시간에는 지금까지 배운 것을 활용해서 게임을 또 만들어봅시다. 사실 게임이야말로 가장 어려운 프로그래밍입니다. 자바스크립트에 대해 더 알아가면서 점점 진화하는 게임을 만들어보죠! 이제는 콘솔은 졸업하고 화면에 직접 표시해봅시다.

조회수:
0
목록
투표로 게시글에 관해 피드백을 해주시면 게시글 수정 시 반영됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright 2016- . 무단 전재 및 재배포 금지. 출처 표기 시 인용 가능.
5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭

댓글

17개의 댓글이 있습니다.
4년 전
안녕하세요. 지금 상속을 하고 있는데

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를 부를수있을거같은데 안되네요.
4년 전
자식은 항상 부모의 매개변수를 모두 포함해야 하고, 매개변수 순서도 맞춰주셔야 합니다. 또한 Object.create는 prototype만 됩니다.
4년 전
감사합니다! 잘 보고 갑니다
4년 전
제로초님 그럼 비동기 통신에서 상속은 어떻게하나요?
ex: function test() {
axios.get(url)
.then((result) => {
test.prototype.result = result;
})
}

const cons_test = new test();

cons_test.result //undefind

이렇게 비동기안에 prototype으로 상속을하면 데이터가 상속받기전에 호출을 해서 undefind가 뜨는거같은데 이런 경우에는 어떻게하죠??
4년 전
한 번 비동기가 실행되면 그 다음부터는 계속 then 안에서 코드가 이어져야 합니다. 자바스크립트 스코프 특성상 저렇게 바깥쪽에서 코드를 쓸 수 없습니다.
4년 전
프로토타입으로 상속을 하려고했는데 그게 안되는군요... ㅠㅠ 알려주셔서 감사합니다.
4년 전
상속은 됩니다만 비동기에 따른 코드 순서를 지키셔야 합니다.
4년 전
감사합니다. 👍
4년 전
안녕하세요?

바로아래의 익명님의 댓글에서 주소를 건네준다는 내용이

프로토타입은 한번만 만들어지고 공유해서 쓰는 것이기에 그런건가요?

감사합니다
4년 전
네네 맞습니다. 한 번만 만들어서 공유해서 씁니다.
6년 전
좋은 강의 감사합니다. 이해가 잘되네요
.apply 메소드를 통해서 상속이 이뤄지고
Object.create() 를 통해서 프로토타입 객체를 상속받는 객체한테 전달해주는 건가요? 전달해줄때는
주소를 건네주는거겠죠?
6년 전
네 그렇습니다.
6년 전
Truck.prototype = Object.create(Vehicle.prototype); 대신
Truck.prototype = Vehicle.prototype; 를 쓴다면
참조복사가 이뤄져 서로 간섭이 일어나겠죠?

그렇다면 Truck.prototype = Object.create(Vehicle.prototype); 는 Vehicle.prototype 객체를 복사해서 Truck.prototype 에 할당한다고 보면 될까요?
6년 전
간섭이라는 게 잘 이해가 안 됩니다. 두 방식 모두 참조인 건 마찬가지입니다. 두 방식의 차이를 본문에 적어두었습니다. 생성자 호출 여부입니다.
6년 전
Vehicle.apply(this, arguments);

여기 arguments를 나머지 매개변수로 하려면 어떻게 해야 할까요?
6년 전
[].slice.call(arguments, 자를 개수) 하시면 됩니다.
6년 전
이해가 잘 되지 않았는디..

Vehicle.apply(this, arguments);

여기 arguments를 ...theArgs 같은 나머지 매개 변수로 바꾸려면
[].slice.call(arguments, 자를 개수) 이걸 하면 된다는 건가용?
6년 전
아아.. es6문법으로 하고싶으신 건가요? ECMAScript 카테고리에 객체 상속 강좌(class) 있습니다
6년 전
아아 그런가용 감사합니당
6년 전
class 강좌 보고 바꿔 봤는데요!

class Vehicle {
constructor (name, speed) {
this.name = name;
this.speed = speed;
}

drive () {
console.log(this.name + ' runs at ' + this.speed);
}
}

const tico = new Vehicle('tico', 50);

tico.drive();

class Sedan extends Vehicle {
constructor (name, speed, maxspeed) {
super(name, speed);
this.maxspeed = maxspeed;
}

boost () {
// super.drive();
console.log(this.name + ' boosts its speed at ' + this.maxspeed);
}
}

const sonata = new Sedan('sonata', 100, 200);

sonata.drive();
sonata.boost();

이렇게 하는게 맞을라나요??

그리고 Vehicle.apply(this, arguments); 이 부분은 super(name, speed);

이걸로 바뀌는 건가용?
6년 전
네네 맞습니다!
6년 전
오오옷 감사합니다 ㅠㅠㅠ

MDN 웹 문서보다 제로초님 글이 더 잘 이해 되네요!!!

곧 나올 node 책도 구매하려 합니당

뷰 강좌도...하핳
6년 전
제로초님 강좌랑 책도 있나요?????
6년 전
질문 있습니다. Sedan의 prototype과 Vehicle의 prototype을 연결했으니까 반대로 Sedan의 메소드 boost 도 Vehicle에서 사용 가능한 거죠?
6년 전
아뇨 안 됩니다. 일방적인 상속이에요
7년 전
와 정말 책보다 이설명이 확실히 도움이 되네요.. 짱이다.
책을 보면..
상속에서 Object.create의 설명이 부족했는데..

"Object.create는 객체를 만들되 생성자는 실행하지 않는 겁니다."

이거 하나로.. 이해가 됐습니다.
7년 전
블로그 널리 홍보해주세요 ㅎㅎ
7년 전
'만족해요'정도로만 투표할 수 있다는 게 안타까울 정도로 훌륭한 강의입니다.
7년 전
'감사합니다' 정로도만 답할 수 있다는 게 안타까울 정도의 극찬이십니다 ㅠㅠ
7년 전
첫번째 예제 6번째 & 11번째 줄 마지막에 ;(세미콜론) 빠진거 같아요.
7년 전
세미콜론은 옵션입니다~
7년 전
Object.create(something.prototype) 에서 막혀서 unikys님 강좌랑 같이 봤어요. 설명도 명쾌하고 잘보고 갑니다.
8년 전
많은 도움이 됩니다. 감사합니다. 저보다 나이도 어리신데 저보다 잘하시는걸보면 정말 열심히해야겠습니다.
8년 전
예제도 재미있고 설명도 잘되있어서 이해가 잘되네요 오늘도 잘보고 갑니다.
8년 전
참 재밌는 예제이군요!!
8년 전
재밌으셨다니 다행이네요 ㅎㅎ
8년 전
오타발견입니다.
function Truck(name, speed, capacity) {
Vehicle.apply(this, argument)
this.capacity = capacity;
}
------------------위의 부분에서
Vehicle.apply(this, argument) => Vehicle.apply(this, arguments) 로
argument => arguments 로 s 빠져서 오류가 나네용
8년 전
감사합니다~