prototype은 자바스크립트에서 객체지향을 지탱하고 있는 핵심적인 개념이래요
자바스크립트는 prototype을 통해서 상속이라는 개념을 제공하고 있답니다.
각각의 객체는 prototype 속성을 가지고 있는데 그것은 자신의 prototype이 되는 다른 객체를 가르키고 또 그 객체의 prototype을 가지며 반복적이고 종점은 prototype이 null인 객체까지 가면 끝이라고 합니다.
From MDN
fucntion foo() {
this.a = 1;
this.b = 2;
}
let boo = new foo()
boo // {a: 1, b: 2}
foo.prototype.b = 3
foo.prototype.c = 4
console.log(boo.a) // boo안에 a가 있니? YES! ==> 1
console.log(boo.b) // boo안에 b가 있니? YES! ==> 2 // boo[prototype] 에도 b가 있지만 가려진다.
console.log(boo.c) // boo안에 c가 있니? NO! 그럼 boo[prototype]에는 있니? YES! ==> 4
console.log(boo.z) // boo안에 z가 있니? NO! 그럼 boo[prototype]에는 있니? NO! boo[prototype][prototype]에는 있니? 아니 그곳은 null이야! ==> undefinded
이런식으로 prototype의 종점(null)까지 확인 하는 모습을 볼 수 있다. 만약 곂치는 값이 있으면 뒤에 있는 값을 속성의 가려짐(property shadowing)
을 하여 앞에 있는 속성을 사용한다.
그러니깐 위의 boo.b
는 b : 2
라는 값과 b : 3
이라는 값이 중복됬지만 앞에 있는 b : 2
라는 속성을 사용했다.
__proto__
위에 코드를 그림으로 그린겁니다!
위 그림에서 Boo의 __proto__
는 Boo의 생성자인 Foo의 prototype
을 가르키고 있습니다!
그림으로 봐도 이해할 수 있듯이 사실 prototype
과 __proto__
는 비교보다는 생성자의 prototype
을 가르키는게 __proto__
다 라고 이해하는게 맞는것 같습니다!
먼저 준비물부터 챙겨보겠습니다!
let vehicle = function(name){
this.name = name;
}
vehicle.prototype.drive = function() {console.log(`${this.name}가 움직입니다.`)}
let car = new vehicle('자동차')
let plane = function(name) {
this.name = name
}
plane.prototype.fly = function() {console.log(`${this.name}가 납니다.`)}
let airplane = new plane('비행기')
airplane.fly() // 비행기가 납니다
airplane.drive() // airplane.drive is not a function
현재 자동차와 비행기를 만들었는데 자동차에는 달리는 기능을 비행기에는 나는 기능을 만들어 줬습니다.
하지만 비행기가 날기 위해선 자동차에 달리는 기능이 필요하기 때문에 자동차에 달리는 기능을 상속해 오려고 합니다.
이때는 Object.create를 이용하면됩니다! MDN에서 Object.create 사용법을 보면 첫번째 인자로 들어가는 prototype 객체를 바탕으로 prototype을 만든다입니다.
다시 한번 해볼까요?
let vehicle = function(name){
this.name = name;
}
// 차량공장을 만들었습니다!
vehicle.prototype.drive = function(){console.log(`${this.name}가 움직입니다.`)}
// 차량공장에 이동기능을 추가 합니다.
let benz = new vehicle('benz')
//이동이 가능한 차량을 만들었습니다!
let plain = function(name){
this.name = name
}
// 비행기공장을 만들었습니다.
plane.prototype = Object.create(vehicle.prototype)
// 비행기공장으로 차량공장의 이동기능을 상속 받아옵니다.
plane.prototype.fly = function() {console.log(`${this.name}가 납니다.`)}
// 비행기공장에 비행기능을 추가 합니다
let B777 = new plane('B777')
// 비행가능하고 이동가능한 비행기를 만들었습니다!
B777.drive() // B777가 움직입니다.
B777.fly() // B777가 납니다.
마지막으로 Class를 이용한 상속 방법을 알아봅시다!
위의 방식과 달리 class를 이용하면 OOP가 무척 쉬워집니다!
위에서 복잡하게 연결했던 방식을 class에서는 아래와 같이 간단하게 연결할 수 있습니다.
class vehicle {
constructor(name) {
this.name = name
}
drive() {
console.log(`${this.name}이 움직입니다`)
}
}
class plane extends vehicle {
constructor(name){
super(name);
}
fly() {
console.log(`${this.name}이 납니다`)
}
}
let a380 = new plane('a380')
a380.drive() // a380이 움직입니다
a380.fly() // a380이 납니다
위와 같이 extends로 간단하게 상속할 수 있고 super
로 this
를 대체 할 수 있습니다!