Prototype과 상속

seunghw·2022년 10월 9일
3
post-thumbnail

시작

워낙 양이 방대하고 어려워서 깊게 이해하는 것보다 얕게라도 확실히 짚고 넘어가고자 다시 봤을 때 바로 이해되게끔 쉽게 풀어서 작성해보려고 합니다.

프로토타입에 대해서

일반적으로 우리가 배열을 가지고 어떠한 작업을 진행할 때 여러 함수들을 선언없이 쓰게 되는데 어떻게 된 걸까요?

let data = [1,2,3]

console.log(data.length) // 3

다음은 data 배열의 길이를 알고 싶을 때 사용하는 Array.length입니다.
선언을 하지도 않았는데 잘 작동하게 됩니다.

data 배열을 자세히 살펴보면 위처럼 [[prototype]]이라는 객체 안에 좀 전에 사용했던 length를 포함하여 우리가 사용하는 다양한 함수들이 들어 있습니다.

그렇기 때문에 우리는 예제처럼 바로 사용할 수가 있었습니다.

이처럼 프로토타입은 객체의 프로토타입(원형)을 가지고 새로운 객체를 생성하는 프로그래밍 방식입니다.
쉽게 말해서 DNA, 유전자라고 생각하면 편한 것 같습니다. 드러나있지 않고 상속도 받는다는 점에 한해서! (모 유튜버가 말해줬던게 생각이 나네요)

상속

상속이란 객체지향 프로그래밍의 핵심 개념이며 어떤 객체의 프로퍼티 또는 메서드를 다른 객체가 상속받아 그대로 사용할 수 있는 것을 말합니다.

const parent = {
  name: "bbb",
  age: "45",
  house: true
 
}

const child = {
  name: "ccc",
  age: "15",
}

// 상속받기
child.__proto__ = parent;

child.house // true

여기서 child.__proto__ = parent;이 부분을 다시 설명하자면
parent가 child의 프로토타입이 되는 것. 반대로 이야기하면 child는 parent의 상속을 받는 것 입니다. 그렇기 때문에 child의 프로토타입이 parent객체를 가리키고 참조하게 됩니다.

실제로 확인해보면 다음과 같이 상속을 받아서
child.house로 확인했을 때 true로 나타나게 됩니다.

동작 과정

1.우선 child의 객체에서 house 프로퍼티를 찾습니다.
2.찾으면 거기서 탐색을 멈추고 없으면 해당 객체의 prototype을 살펴봅니다.
3.house 프로퍼티를 발견하여 탐색을 종료하고 출력해줍니다.

의 순서로 진행이 됩니다. 또한 상속은 연속으로도 이루어 질 수 있습니다.

쓰는 이유?

위처럼 객체의 상속을 구현하여 중복을 제거하고 기존 코드들을 적극적으로 재사용하기 위해서 사용하게 됩니다. 프로토타입은 어떤 객체의 상위 객체의 역할을 하는 객체이며 다른 객체에 공유 프로퍼티를 제공합니다.
프로토타입을 상속받은 하위 객체는 상위 객체의 프로퍼티를 자신의 프로퍼티처럼 자유롭게 사용할 수 있습니다.

프로토타입체인

const human = {
  head: 1,
  hello() {
    console.log("hi");
  }
}

const parent = {
  name: "bbb",
  age: "45",
  house: true,
 
}

parent.__proto__ = human;

const child = {
  name: "ccc",
  age: "15",
}

child.__proto__ = parent;

//1번
child.age // 15

//2번
child.head // 1

첫 예제에서 human을 더 추가해서 parent에 상속을 해주었습니다.

1번에서 age를 찍었을때는 15가 나오게 되는데 위의 동작원리와 동일하게 child의 객체에서 age 프로퍼티를 바로 찾아서 탐색을 중지하고 age가 15로 나타나게 됩니다.

동작 과정

2번에서는 head가 1로 잘 나타나게 되었는데 동작과정 다음과 같습니다.

  1. 우선 child의 객체에서 head 프로퍼티를 찾습니다.
  2. 없어서 해당 child 객체의 prototype을 살펴봅니다.
  3. child객체의 prototype은 parent를 참조하고 있기 때문에 parent를 탐색합니다.
  4. child 객체의 prototype 즉, parent를 탐색한 결과 없어서 parent의 prototype을 또 타고 들어가서 찾아봅니다.
  5. parent의 prototype은 human을 참조하고 있기 때문에 human을 탐색합니다.
  6. head 프로퍼티를 발견하여 탐색을 종료하고 출력해줍니다.

실제 child객체 내부를 살펴보면 다음과 같습니다.

이렇게 해당 객체부터 시작해서 프로토타입 내부를 도장깨기마냥 찾을 때까지 순차적으로 타고 들어가 검색하는 것을 프로토타입 체인이라고 합니다.

이렇게 프로토타입 체인은 상속프로퍼티 검색을 위한 메커니즘입니다.

이에 반해, 프로퍼티가 아닌 식별자는 스코프 체인에서 검색합니다. 다시 말해서, 자바스크립트엔진은 함수의 중첩 관계로 이루어진 스코프의 계층적 구조에서 식별자를 검색합니다. 따라서 스코프체인은 식별자 검색을 위한 메커니즘입니다.

child.house

위를 보시면 먼저 스코프체인에서 child 식별자를 검색합니다. 전역에서 선언되었으므로 전역스코프에서 찾을 수 있고, 다음 child객체의 프로토타입 체인에서 house를 찾습니다.

☘️ 이처럼 스코프체인과 프로토타입 체인은 서로 협력하면서 식별자와 프로퍼티를 검색하는데에 사용됩니다.

생성자함수를 활용하여 중복코드 줄이기

간단한 상속을 __proto__로 구현했었는데요. 만약에 왼쪽같은 구조가 아니라 오른쪽같은 구조라면? 게다가 가짓수가 많다면 __proto__를 반복해서 작성하면 굉장히 피로하겠죠
그래서 생성자함수를 활용하여 다음과 같이 사용합니다.

const human = function(name){
    this.name = name;
}

human.prototype.head = 1;
human.prototype.eyes = 2;
human.prototype.morning = function () {
    console.log("Good morning~");
};
human.prototype.afternoon = function () {
    console.log("Good afternoon~");
};

const h1 = new human("seunghwan");
const h2 = new human("kim");

h1.morning() // 

// h1.__proto__ = human;
// h2.__proto__ = human;

h1.morning()을 실행시켰을때 잘 나옵니다.
이렇게 한번만 만들어주면 생성자로 만들어진 모든 객체에 하나하나 작업해줄 필요는 없습니다.
위와같이 사용하면 중복코드를 줄일 수 있습니다.

참조

https://developer.mozilla.org/ko/docs/Web/JavaScript/Inheritance_and_the_prototype_chain#%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85_%EC%B2%B4%EC%9D%B8%EC%9D%84_%EC%9D%B4%EC%9A%A9%ED%95%9C_%EC%83%81%EC%86%8D
https://www.youtube.com/watch?v=wT1Bl5uV27Y
https://www.inflearn.com/course/%EB%AA%A8%EB%8D%98-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EA%B3%A0%EA%B8%89-1/dashboard

profile
Lumos

1개의 댓글

comment-user-thumbnail
2022년 10월 12일

어려운 개념이었는데 정리를 잘 해주신 것 같아요. 잘 보고 갑니다. 👍

답글 달기