안녕하세요.
이번 글에서는 자바스크립트에서의 상속 - (Prototype) 핵심만 알려드리겠습니다.
1. prototype
1.1 prototype이란?
지난 시간에 constructor를 이용해 객체를 여러 개 만드는 법을 배웠는데요.
근데 constructor로 객체를 만들면,
Prototype이라는 항목이 constructor안에 자동으로 생성됩니다.
간단한 예시를 들어보겠습니다.
function Person(name){
this.name = name;
}
var person1 = new Person('kim');
console.log(Person.prototype);
construcor로 객체를 만들고 prototype이란 값을 찍어보았습니다..
이런 이상한 값이 출력됩니다.
왜 constructor로 객체를 만들었는데, prototype이라는 항목이 생성될까요?
저희는 지금 상속에 관해 배우고 있습니다.
prototype은 상속을 구현할 수 있는 일종의 유전자인데요.
저희가 부모의 유전자를 통해 키와, 외모를 물려받듯,
객체도 prototype을 통해 객체의 속성과 메서드를 물려받을 수 있습니다.
1.2 prototype으로 상속 구현하기
prototype에 속성이나, 메서드를 넣으면 모두 자식 객체가 물려받습니다.
function Person(name){
this.name = name;
}
Person.prototype.age = 20;
var person1 = new Person('kim');
console.log(person1.age); //20
이렇게 객체를 추가하듯이 prototype에 함수나 값을 추가하고 사용하시면,
상속을 구현하실 수 있습니다.
1.3 constructor vs prototype
constructor내부에 값을 집어넣어 상속을 구현할 수도 있고,
prototype에 값을 추가해 상속을 구현할 수도 있습니다.
//1. constructor
function Person(name) {
this.name = name;
}
//2. prototype
function Person() {}
Person.prototype.name = name;
만약 자식이 값을 가지는 걸 원하면 constructor로 상속을 구현하면 됩니다.
하지만 부모가 값을 가지고 있어서, 참조하게 하고 싶으면 prototype을 쓰면 됩니다.
보통 함수들은 porototype에 넣는데요.
prototype에 함수를 넣어 부모가 가진 값을 상속할 수 있게 만드는 거죠. (내장함수 라고도 합니다.)
2. __proto__
2.1 __proto__란?
혹시 constructor로 객체를 만들면,
prototype이 constructor 내부에 생성된다는 거 기억하시나요?
하지만 constructor로 만든 객체(인스턴스) 에는 prototype이 존재하지 않습니다.
function Person(name){
this.name = name;
};
console.log(Person.prototype) //(많이 뭔가 나옴)
let obj = {a: 1, b:2}
console.log(obj.prototype); //undefined
위 예시를 보면 일반 객체에는 prototype이 존재하지 않는 모습입니다.
그럼 일반 객체에서는 prototype이 없으니 상속을 구현할 수 없는 건가요?
아니요 __proto__를 이용하면 일반 객체에서도 상속을 구현할 수 있습니다.
2.2 사용방법
const obj1 = {age : 10};
const obj2 = {};
obj2.__proto__ = obj1;
console.log(obj2.age); //10
간단하게 __proto__를 이용해서 상속을 구현한 모습입니다.
💡 **proto** 로 상속을 구현하는 방법은 성능이 안 좋아질 수도 있습니다.
그러니 상속을 구현하고 싶으면,
- constructor
- class
- Object.create()
중에 사용하세요.
제 개인적으론 상속 구현은 대부분 class로 만드니,
만드신다면 class로 구현하는 게 좋을 것 같습니다.
2.3 prototype과 __proto__ 차이
prototype은 유전자입니다.
자식에게 넘겨주고 싶은 속성이나 메서드를 정의할 수 있습니다.
__proto__로는 받은 유전자에 접근할 수 있습니다.
부모에게 받은 prototype을 참조할 수 있죠.
위에 개념을 종합해 보면
__proto__는 받은 유전자에 접근할 수 있기에, 부모의 prototype과 같은 개념입니다.
function People(name) {
this.name = name
};
var people1 = new People();
console.log(peopl1.__proto__ === People.prototype) //true
위 예시처럼 그냥 __proto__와 부모 prototype은 같다고 생각하시면 됩니다!
3. 왜 prototype을 알아야 할까?
왜 우리가 prototype을 알아야 할까요?
자바스크립트는 프로토타입 기반 객체지향 프로그래밍 언어입니다.
자바스크립트의 대부분은 객체이며, 또 프로토타입을 가지고 있습니다.
자바스크립트는 오브젝트에서 값을 뽑을 때 다음과 같은 순서로 확인합니다.
- 지금 사용하려는 객체에 값이 있는지 검사
- 없으면 부모 객체의 값을 검사
이 과정을 더 이상 부모 객체가 없을 때까지 검사 후 값을 가져옵니다.
그래서 객체에는 모든 값이 존재하지 않아도 됩니다.
필요한 값은 프로토타입에 넣어두고 필요할 때만 가져오면 되니깐요
예를 들어 js에서 배열을 요소를 반복할 수 있는,
배열 내장함수 forEach()를 예시로 들겠습니다.
let arr = [1,2,3];
console.log(arr) //[1, 2, 3]
arr.forEach((val) => {
console.log(val); //1, 2, 3
});
배열을 출력하면 당연하게도 [1, 2, 3]이 출력됩니다.
배열에 forEach함수는 존재하지 않는데 어떻게 사용 가능한 것일까요?
이유는 바로 배열의 prototype에 forEach가 존재하기 때문입니다.
수많은 배열의 내장 함수들이 보이시죠?
이제 prototype이 왜 필요하신지 감이 좀 잡히실 거 같은데요.
저 수많은 내장 함수들을 직접 구현하지 않고, prototype에서 상속받아 쉽게 사용할 수 있는 거죠.
3.1 자바스크립트의 동작 방식
근데 한 가지 이상한 점은,
prototype은 constructor로 객체를 만들 때 자동으로 생성되는 거라고 배웠습니다.
배열은 let arr = [1, 2 ,3]; 이렇게 만들었는데, 왜 prototype이 존재할까요?
이유는 자바스크립트에서 아래 코드가 동일하기 때문입니다.
var arr = [1, 2, 3]; //1번
var arr = new Array(1, 2, 3); //2번
저희는 보통 배열을 만들 때 1번 방식을 쓰는데요.
1번은 사람이 편하게 코딩하기 위해 만든 것이고,
1번 코드는 2번 방식으로 내부적으로 js가 해석합니다.
근데 2번 방식은 constructor로 객체를 만드는 방법과 동일합니다.
function Person(name, age) {
this.name = name;
}
var person1 = new Person("John");
위에 new Person은 “Person constructor에서 객체를 뽑아주세요” 란 뜻입니다.
마찬가지로 new Array는 “Array constructor에서 객체를 뽑아주세요” 란 뜻이겠네요.
또 Person에서 생성된 자식 객체는 Person의 유전자(prototype)에 있는 속성이나 메서드 들을 사용 가능합니다.
그럼 Array의 prototype 에는 뭐가 있을까요? 확인해 보겠습니다.
console.log(Array.prototype)
Array의 prototype에 메서드가 숨어 있었네요!
이게 내장함수의 원리였습니다!
'javascript > (es6)핵심만 시리즈' 카테고리의 다른 글
[JS ES6]-[17] 동기, 비동기 핵심만 이해하기(1) - 이벤트루프 (0) | 2023.09.09 |
---|---|
[JS ES6]-[16] 상속 핵심만 이해하기(3) - class(클래스) (0) | 2023.09.09 |
[JS ES6]-[14] 상속 핵심만 이해하기(1) - constructor(생성자) (0) | 2023.09.08 |
[JS ES6]-[13]destructuring(구조분해 할당) 핵심만 이해하기 (2) | 2023.09.08 |
[JS ES6]-[12]arguments/rest parameter(나머지 연산자) 핵심만 이해하기 (0) | 2023.07.02 |