[JavaScript]프로토 타입(Prototype)

LMH·2022년 11월 18일
0
post-thumbnail

프로토 타입

오늘은 자바스크립트의 핵심적인 요소 중에 하나라고 할 수 있는 프로토 타입(Prototype)에 대해서 정리해보고자 합니다. 자바스크립트는 프로토타입 기반 언어라고 합니다. 자바스크립트에서 상속을 위해 프로토 타입이라는 방식을 사용합니다. 그리고 상속을 통해 객체지향 프로그래밍을 할 수 있게 됩니다.

그렇다면 정확하게 프로토 타입이란 무엇일까요? 프로토 타입은 원형 객체를 의미합니다. 이 객체는 모든 객체가 메소드와 속성들을 상속 받기 위한 템플릿입니다. 그리고 프로토 타입 객체 또한 상위 프로토 타입 객체로 부터 메소드와 속성을 상속 받을 수 있습니다. 이를 프로토 타입 체인(prototype chain)이라 부릅니다.

정확하게는 상속되는 속성과 메소드들은 객체 내부가 아니라 객체 생성자의 프로토 타입 속성에 정의되어 있습니다.

.prototpye

Person.prototpye은 Person 생성자의 프로토 타입 객체를 의미합니다. 크롬 개발자 도구에서 console.log(Person.prototype)을 출력해보면 Person 생성자에 [[prototype]]이라는 속성이 존재하고 이 속성은 Object의 프로토타입 객체임을 알 수 있습니다. Person 생성자에서 valueOf 메소드를 사용할 때, 생성자의 프로토 타입 객체에 valueOf 메소드가 없기 때문에 Object 객체의 프로토 타입 객체에 있는 메소드를 참조하여 사용하게 됩니다.

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

  run() {
    console.log(`${this.name}은 달리기를 합니다.`);
  }
}

console.log(Person.prototype); // Person의 프로토 타입 객체 호출
//  ▼ {constructor: ƒ, run: ƒ}
//   ► constructor: class Person
//   ► run: ƒ run()
//   ► [[Prototype]]: Object  // Person의 프로토타입 객체의 속성인 프로토 타입 객체

Person.valueOf();
// class Person {
//   constructor(name, age) {
//     this.name = name;
//     this.age = age;
//   }

//   run() {
//     console.log(`${this.name}은 달리기를 합니다.`);
//   }
// }

Person.prototype.constructor === Person; // true

사실 위의 코드 처럼 클래스 내부에 함수를 정의하는 것은 메모리 자원을 낭비하는 코드입니다. 인스턴스 객체를 생성 할때마다 정의된 메소드를 생성하기 때문입니다. 그렇기 때문에 생성자에 메소드를 추가하기 위해서는 다음과 같이 작성하는 것이 좋습니다.

Person.prototype = functuon run() {
  console.log(`${this.name}은 달리기를 합니다.`);
   }
}

이번에는 Person 생성자의 인스턴스 객체를 생성해 보겠습니다. 인스턴스에 _ _proto__ 속성를 참조하면 Person 생성자의 프로토 타입 객체가 참조되는 것을 알 수 있습니다. jack 이라는 인스턴스 객체는 Person 생성자 내부에 구현한 run이라는 메소드와 Person 생성자의 프로토 타입 객체에 속성으로 존재하는 Object 객체의 프로토 타입 객체의 메소드까지 모두 사용할 수 있습니다.

특정 객체의 프로토 타입 객체에 바로 접근하는 공식적인 방법은 없습니다. 하지만 많은 브라우저에서 생성자의 프로토 타입 속성에서 파생된 _ _ proto__ 속성을 통해 특정 객체의 프로토 타입 객체에 접근할 수 있도록 구현되어 있습니다.

const jack = new Person('Jack', 30);

console.log(jack.__proto__);
//  ▼ {constructor: ƒ, run: ƒ}
//   ► constructor: class Person
//   ► run: ƒ run()
//   ► [[Prototype]]: Object

Person.prototype === jack.__proto__; // true
Person.prototype.run === jack.run; // true

프로토 타입 체인

인스턴스 객체의 메소드가 호출되면 인스턴스 내부에 해당 메소드가 있는지 확인 후 없다면 생성자의 프로토 타입 객체에 해당 메소드가 있는지 찾게 됩니다. 이렇게 프로토 타입을 타고 올라가며 메소드에 접근하는 것을 프로토 타입 체인이라고 합니다.

jack.valueOf() // Person {name: 'Jack', age: 30}

프로토 타입 체인이 일어나는 과정

  1. 브라우저는 우선 jack 객체가 valueOf() 메소드를 가지고 있는지 체크합니다. -> 존재하지 않음

  2. jack의 프로토타입 객체(Person() 생성자의 프로토타입)에 valueOf() 메소드가 있는지 체크합니다. -> 존재하지 않음

  3. Person() 생성자의 프로토타입 객체의 프로토타입 객체(Object() 생성자의 프로토타입)가 valueOf() 메소드를 가지고 있는지 체크합니다. 프로토 타입 객체 내에 메소드가 있으니 호출하게 됩니다.

프로토 타입 체인에서는 객체의 메소드와 속성들이 다른 객체로 복사되는 것이 아니라 위와 같은 방식으로 체인을 타고 올라가며 접근하게 됩니다.

프로토 타입의 수정

생성자의 프로토 타입 객체의 속성을 변경하면, 생성자로 생성한 인스턴스 객체는 변경된 속성이나 메소드를 사용할 수 있습니다. 이는 생성순서와 상관 없이 자동으로 업데이트 되므로 모든 인스턴스가 공유 할 수 있습니다.

tom.run() // tom은 달리기를 합니다.
Person.prototype.run = function() { console.log(`${this.name}은 뛰기 시작합니다.`);}
tom.run() // Jack은 뛰기 시작합니다. 
jack.run() // Jack은 뛰기 시작합니다.

Object.Create()

create 메소드를 이용하하여 tom이라는 인스턴스 객체를 생성해 보겠습니다. 여기서 create 메소드는 jack 객체를 프로토 타입으로하는 tom 객체를 생성합니다. 그리고 tom의 프로토 타입 객체를 확인해보면 Jack이 출력되는 것을 알 수 있습니다.

const tom = Object.create(jack); 
console.log(tom.__proto__);

// Person {name: 'Jack', age: 30}
// age : 30
// name : "Jack"
//  ▼ [[Prototype]]: Object
//	 ► constructor : class Person
//   ► run : ƒ run()
//   ► [[Prototype]] : Object

정리

오늘은 프토토 타입에 대해서 정리를 하였습니다. 프로토 타입에 의해 자바스크립트로도 객체지향 프로그래밍이 가능하게 되었습니다. 자바 언어와 같이 은닉을 위한 private 메소드나 더 깊은 추상화 단계를 구현할 수 있는 interface 기능은 없지만 프로토 타입 체인에 의해 클래스 메소드가 인스턴스 객체로 상속이 가능하게 되는 것을 알 수 있었습니다.

reference : https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Object_prototypes

profile
새로운 것을 기록하고 복습하는 공간입니다.

0개의 댓글