-
320x100
출처: https://www.zerocho.com/category/JavaScript/post/573d812680f0b9102dc370b7
프로토타입 체인을 이용하면 부모가 가진 기능에 더해 새로운 기능을 추가할 수 있습니다.
SASS의 @extend와 비슷한 기능이죠.
우선 생성자 하나를 만들어봅니다. 생성자 함수는 대문자로 시작했죠?
function Vehicle(name, speed){ this.name = name; this.speed = speed; }
이제 new Vehicle()을 통해 고유의 name과 speed를 갖는 객체를 만들 수 있게 됐습니다.
그런데 이 생성자 함수를 통해 만들어진 객체들에게 공통적인 기능(함수)을 추가하려고 해요.
그럴 때는 this를 쓰는 대신, prototype에 메서드로 추가하는 게 낫죠.
Vehicle.prototype.drive = function () { console.log(`${this.name}은(는) ${this.speed}의 속도로 달립니다.`); }
이렇게 하면 Vehicle()의 프로토타입 객체에 drive라는 메서드가 추가됩니다.
여기서 잠깐 복습! 메서드 내의 this는 어디에 바인딩 된다고 했죠? 바로 메서드를 호출한 객체로 바인딩됩니다.
이제 이 생성자 함수를 통해 새로운 객체를 만들어봅니다.
경차 하나를 만들어볼게요.
var tico = new Vehicle("tico", 50); tico.drive(); //"tico은(는) 50의 속도로 달립니다."
잘 달리네요 :D
이번엔 세단을 한 번 만들어볼까 합니다.
어쨌든 얘도 자동차니까 new Vehicle()을 통해 만들 거긴 한데, 좀 특별한 부스트 기능을 넣고 싶어요!
그럴 때 쓰는 게 상속입니다.
function Sedan(name, speed, maxSpeed) { this.name = name; this.speed = speed; this.maxSpeed = maxSpeed; }
Sedan()이라는 새로운 생성자 함수를 만들었습니다.
인자로 name, speed, maxSpeed 세 개를 받네요. 그런데 이 중 두 개는 Vehicle()과 동일합니다.
즉, this.name = name; this speed = speed; 부분을 다시 써주는 건 비효율적입니다.
이 두 속성은 Vehicle()로부터 가져오고, maxSpeed만 따로 넣어주려고 합니다.
이건 apply()라는 메서드를 통해 구현할 수 있습니다.
function.apply(thisArg, [argArray])
apply()는 함수를 호출하여, 1번째 인자를 함수 내부의 this로 바인딩 하고, 2번째 인자를 호출한 함수의 인자로 넘기는 기능이 있습니다.
잠깐만 예제를 살펴보죠.
var person = { whois: function (country) { console.log(this.firstName + " " + this.lastName + " from " + country); } } var nana = { firstName: "nana", lastName: "kim" } person.whois.apply(nana, ["korea"]);
위 코드에선 person.whois()이라는 함수에 apply를 호출했습니다.
그리고 this의 내용을 nana 객체의 것으로 대체했음을 알 수 있습니다.
본론으로 돌아와서, 그럼 Vehicle()의 속성을 받아오려면 어떻게 해야할까요?
function Sedan(name, speed, maxSpeed) { Vehicle.apply(this, arguments); this.maxSpeed = maxSpeed; }
여기서 arguments는 넘어온 인자를 나타내는 유사배열입니다.
즉, Vehicle이라는 함수에다 this를 바인딩하고, 그 인자는 arguments로 하겠다~라는 소리네요.
새 차를 만들어볼까요?!
var sonata = new Sedan("sonata", 100, 200);
Sedan()이 실행되면, Vehicle.apply()를 통해 Vehicle 함수가 실행됩니다.
이때 Vehilce()함수는 두 개의 인자를 필요로 하는데, 그걸 this(여기선 sonata)로부터 받아오게 합니다.
구체적인 인자는 arguments 안에 들어있고요.
그래서 콘솔에 찍어보면...
Sedan { name: "sonata", speed: 100, maxSpeed: 200, __proto__: Object }
Sedan()만 호출했을 뿐인데도 새 Vehicle이 잘 탄생했네요!
이제 소나타로 달려볼까요?!
sonata.drive(); //Uncaught TypeError: sonata.drive is not a function
엌 에러가 뜨네요ㅜㅜ
왜냐, drive() 메서드는 Vehicle의 prototype 객체에 들어있습니다.
하지만 sonata가 __proto__로 연결하고 있는 prototype 객체는 Vehicle.prototype이 아닌, Sedan.prototype입니다.
sonata.__proto__ === Vehicle.prototype //False sonata.__proto__ === Sedan.prototype //True
따라서 Sedan.prototype을 손봐줄 필요가 있습니다.
Sedan.prototype = Object.create(Vehicle.prototype);
Object.create()는 지정된 프로토타입 객체와 속성을 갖는 새로운 객체를 만듭니다. (MDN)
그래서 Vehicle.prototype을 프로토타입 객체로 갖는 새 객체를 만들어, Sedan.prototype에 넣어준 셈입니다.
Object.create는 객체를 만들되 생성자는 실행하지 않습니다.
Sedan.prototype === Vehicle.prototype //False
Sedan.prototype = Vehicle.prototype처럼 바로 넣어준 게 아니라,
새 객체를 만들어넣어줬기 때문에 엄밀히 말하면 두 함수는 서로 다른 프로토타입 객체를 갖습니다.
다만 Vehicle.prototype의 내용을 Sedan.prototype이 가지게 된 것 뿐이죠.
그런데, 뜨든. 한 가지 문제가 있습니다.
Sedan.prototype.constructor === Vehicle //True
prototype.constructor는 당연히 그 생성자를 가리켜야 하는데,
Sedan의 생성자는 Vehicle을 가리키고 있네요 켘
틀린 점은 고쳐주고 넘어갑시다.
Sedan.prototype.constructor = Sedan;
그리고 Sedan만의 특별한 기능을 추가해줍니다. 아까 넣으려고 했던 부스트 기능이요!
Sedan.prototype.boost = function () { console.log(`부스트!!! 이제 ${this.name}은(는) ${this.maxSpeed}의 속도로 달립니다.`); }
그럼 이제 세단이 잘 동작하는 걸 볼 수 있습니다.
var sonata = new Sedan("sonata", 100, 200); sonata.drive(); //"sonata은(는) 100의 속도로 달립니다." sonata.boost(); //"부스트!!! 이제 sonata은(는) 200의 속도로 달립니다."
응용하면 짐을 싣는 트럭도 만들어볼 수 있겠네요!
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(`${weight - this.capacity}만큼 중량 초과입니다.`); } console.log(`${weight} 만큼의 짐을 실었습니다.`) } var boongboong = new Truck("boongboong", 40, 100); boongboong.drive(); //"boongboong은(는) 40의 속도로 달립니다." boongboong.load(130); //"30만큼 중량 초과입니다."
+
개인적으로 공부한 내용이라 틀린 점이 있을 수 있습니다.
더 정확한 내용을 알려주신다면 감사하겠습니다 :)
728x90'Blog > JavaScript' 카테고리의 다른 글
[JS] 요소의 요모조모 (1) - 문서 내 요소의 크기와 위치 (0) 2019.12.03 [JS] Text RPG 만들기 (1) 2019.11.12 [JS] 브라우저의 객체 (0) 2019.11.04 [Inside JS] 2. 함수와 프로토타입 체이닝 (0) 2019.09.10 [Inside JS] 1. 자바스크립트 데이터 타입과 연산자 (0) 2019.09.05 댓글