[JavaScript] 프로토타입(prototype)

rsuubinn·2023년 1월 13일
0

JavaScript

목록 보기
7/10
post-thumbnail

📍 프로토타입(prototype)

자바스크립트는 흔히 프로토타입 기반 언어(prototype-based language) 라 불린다.
모든 객체들이 메소드와 속성들을 상속 받기 위한 템플릿으로써 프로토타입 객체(prototype object) 를 가진다는 의미이다.
상속되는 속성과 메소드들은 각 객체가 아니라 객체의 생성자의 prototype 이라는 속성에 정의되어 있다.

class Human {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  sleep() {
    console.log(`${this.name}은 잠에 들었습니다.`);
  }
}

let kimcoding = new Human('김코딩', 30);

Human.prototype.constructor === Human; // true (Human 클래스의 생성자 함수는 Human 이다.)
Human.prototype === kimcoding.__proto__; // true (Human 클래스의 프로토타입은 Human 클래스의 인스턴스인 kimcoding '__proto__' 이다.)
Human.prototype.sleep === kimcoding.sleep; // true (Human 클래스의 sleep 메서드는 프로토타입에 있으며, Human 클래스의 인스턴스인 kimcoding에서 kimcoding.sleep으로 사용할 수 있다.)

프로토타입 이해하기

class Machine { // 복사하는 기계
  constructor(q, w) {
    this.q = 'strike'; // 복사된 object가 기본으로 가질 속성
    this.w = 'snowball';
  }
}

let machine1 = new Machine(); // 부모 Machine 가 자식 machine1 생산
console.log(machine1); // {q: 'strike', w: 'snowball'}

일반적인 클래스 생성 과정이다.
하지만 Machine.prototype 을 개발자 도구에 입력하면
만든적 없는 prototype 이라는 속성의 결과값이 출력된다.

Machine 에는 자동으로 prototype 이라는 공간이 생긴다.
prototype유전자 라고 생각하면 이해가 쉽다.


prototype 은 생성자 함수에 사용자가 직접 넣는 거, __proto__ 는 new를 호출할 때 prototype을 참조하여 자동으로 만들어진다.
생정자 함수에는 prototype, 생성자로부터 만들어진 객체(인스턴스)에는 __proto__ 에 생성자의 prototype이 들어간다.
new Machine() 로써 만들어진 모든 객체(machine1)는 결국 Machine.prototype 객체 와 내부적으로 [[Prototype]] 링크로 연결된다.
결국 machine1Machine상호 연결된 두 개의 객체가 된다.

class Machine { 
  constructor(q, w) {
    this.q = 'strike'; 
    this.w = 'snowball';
  }
}
Machine.prototype.name = 'robot'; // 프로토타입에 네임이라는 속성 추가

let machine1 = new Machine(); 
machine1.name; // 'robot'

machine1에 name 속성을 구현한 적이 없는데 'robot' 이라는 출력값이 나온다.
하지만 machine1 에는 name 속성이 존재하지 않는다.

이러한 이유가 무엇일까?

  1. machine1에 name 속성이 있으면 속성값을 출력
  2. machine1에 name 속성이 없으면 machine1의 부모 유전자(prototype)에서 name 속성을 찾음
  3. prototype에 name 속성이 없으면 그 위 prototype에서 찾음
  4. 이러한 과정을 반복해 최상위 프로토타입에도 name 속성이 없으면 탐색을 종료하고 undefined를 반환한다.

객체와 객체를 연결해야 하는 이유는?

class Machine { 
  constructor(q, w) {
    this.q = 'strike'; 
    this.w = 'snowball';
    this.action = function(){
      console.log('move');
    }
  }
}

let machine1 = new Machine();

class Machine { 
  constructor(q, w) {
    this.q = 'strike'; 
    this.w = 'snowball';
  }
}
Machine.prototype.action = function () {
  console.log('move');
}

let machine1 = new Machine();

this에 넣은 것은 객체 하나를 만들 때 마다 메소드도 하나씩 만들어지지만, prototype은 모든 객체가 공유를 하고 있기 때문에 한 번만 만들어져 불필요한 메모리 사용을 줄일 수 있다.

mdn 검색 시 Array.prototype.메소드 인 이유

let arr = [5, 3, 4, 2, 1];
arr.sort();
console.log(arr); // [1, 2, 3, 4, 5]

배열에서 .sort(), .filter(), .reduce() 가 사용 가능한 이유도 위와 같다.
arr를 선언할 때 sort() 메서드를 구현하지 않았는데 사용이 가능하다.

흔히 mdn에 Array 메서드를 검색했을 때 .prototype 이 붙는 이유이다.

배열을 만들 때 아래의 두 가지 방법이 있다.

let arr = [5, 3, 4, 2, 1];
let arr = new Array(5, 3, 4, 2, 1);

arr의 부모 유전자(prototype)에 sort() 가 구현되어 있어 자식인 arr가 sort() 사용이 가능하다.

Array.prototype.hello = 'hi!';
arr.hello // 'hi!';

위처럼 prototype 에 저장하면 자식들도 사용이 가능하다.

배열(arr)는 Array 클래스의 인스턴스 이며, 프로토타입에는 다양한 메서드가 존재한다.

📍 정리

객체에 존재하지 않는 프로퍼티 접근을 시도하면 해당 객체 내부 [[Prototype]] 링크를 따라 다음 수색 장소를 결정한다.
모든 일반 객체의 최상위 프로토타입 연쇄는 내장 Object.prototype 이고 이 지점에서도 찾지 못하면 탐색이 종료 된다.

두 객체를 서로 연결짓는 가장 일반적인 방법은 함수 호출 시 new 키워드를 앞에 붙이는 것이다.
new 키워드는 일반 함수 호출 + '객체' 생성 이라는 잔업을 더 부과하는 지시자 이다.
const f = new Foo() 를 실행하면 Foo 함수가 실행되고, 객체가 생성되어 변수 f에 할당된다.

const f = new Foo();
typeof f; // object
typeof Foo; // function
  • constructor 는 내가 선언한 생성자 함수(Foo)를 가리킨다. new 키워드와 함께 함수를 호출할 경우 constructor 함수를 실행하고 부수효과로 객체가 생성된다.
  • prototype 은 생성자 함수에 정의한 모든 객체가 공유할 원형이다.
  • __proto__ 는 [[Prototype]] 링크이다. 생성자 함수에 정의해두었던 prototype을 참조한다.

참고

위 동영상 강의 보고 블로글 글 읽는 걸 추천합니다 🧔🏻‍♀️

profile
@rsuubinn

0개의 댓글