- 
                     
                     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 //FalseSedan.prototype = Vehicle.prototype처럼 바로 넣어준 게 아니라, 새 객체를 만들어넣어줬기 때문에 엄밀히 말하면 두 함수는 서로 다른 프로토타입 객체를 갖습니다. 다만 Vehicle.prototype의 내용을 Sedan.prototype이 가지게 된 것 뿐이죠. 그런데, 뜨든. 한 가지 문제가 있습니다. Sedan.prototype.constructor === Vehicle //Trueprototype.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 댓글