[JavaScript] Prototype

mechaniccoder·2020년 12월 10일
0
post-thumbnail

[[prototype]] vs proto

[[prototype]]과 proto 의 차이를 알아보겠습니다. 자바스크립트에서는 객체의 숨김 프로퍼티로 [[prototype]]를 가지고 있습니다. 어떤 프로퍼티를 찾으려고 할때 만약 객체에 이 프로퍼티가 존재하지 않는다면 [[prototype]] 프로퍼티가 참조하는 다른 객체에서 이를 찾으려고 시도합니다. 여기서 이 객체를 바로 프로토타입이라고 합니다.

proto 을 요즘엔 잘 쓰지 않는다고 합니다. 요즘엔 보통 Object.getPrototypeOf나 Object.setPrototypeOf 메서드를 활용합니다.

그럼 proto 는 뭘까요? proto 는 [[prototype]]의 getter이자 setter입니다. getter와 setter는 마치 프로퍼티처럼 사용할 수가 있습니다.


this와 prototype

this는 prototype에 영향을 받지않습니다. this는 알고 있듯이 메서드를 호출하는 런타임에서의 객체를 의미하죠. 코드를 확인해봅시다.

const animal = {
  eats: true,
  setName() {
    this.name = "seunghwan";
  },
};

const rabbit = {
  jumps: true,
  __proto__: animal,
};

rabbit.setName();

console.log(animal); // { eats: true, setName: [Function: setName] }
console.log(rabbit); // { jumps: true, name: 'seunghwan' }

위 코드를 보면 알 수 있듯이 this는 무조건 .앞의 객체를 의미합니다.


for...in과 prototype

for...in문을 사용해 객체의 프로퍼티를 출력하면 객체의 프로퍼티뿐만 아니라 프로토타입의 프로퍼티도 출력이됩니다. 따라서 Object.prototype.hasOwnProperty 메서드를 활용하면 걸러낼 수 있습니다.

// for...in문은 prototype의 프로퍼티도 순회대상에 포함합니다.
const animal = {
  eats: true,
};

const rabbit = {
  jumps: true,
  __proto__: animal,
};

console.log(Object.keys(rabbit)); // jump만 반환

for (const property in rabbit) {
  console.log(property); // jumps, eats
}

// prototype의 프로퍼티를 걸러내기 위해서 obj.hasOwnProperty 메서드를 활용합니다.
for (const property in rabbit) {
  if (rabbit.hasOwnProperty(property)) {
    console.log("자신의 프로퍼티:", property); // jumps
  } else {
    console.log("상속 프로퍼티:", property); // eats
  }
}

그렇다면 왜 hasOwnProperty는 출력되지 않을까요? 그건 객체의 플래그 중에 enumerable이 false로 설정되어 있기 때문입니다. 이렇게 enumerable이 false로 설정되어 있는 대표적인 메서드들은 다음과 같습니다.

  • Object.keys()
  • Object.values()

Prototype 메서드

모던 자바스크립트에서는 프로토타입에 관한 메서드들이 추가됐습니다.

  • Object.create(proto, [descriptor])
  • Object.getPrototypeOf(obj)
  • Object.setPrototypeOf(obj, proto)

[[prototype]]의 getter이자, setter인 proto를 활용하는 것 대신에 Object 생성자 함수의 메서드를 사용하세요.

🤔 왜 proto를 사용하는 것이 좋지 않을까요?

proto를 사용해 [[prototype]]을 변경하는 것은 객체 프로퍼티 접근 최적화 알고리즘을 망치게 됩니다. 따라서 자바스크립트에서는 객체를 초기에 생성할때만 프로토타입을 설정하도록 권고하고 있습니다.

😮 객체를 복사할 수도 있습니다.

제가 지금까지 알고있는 객체를 복사하는 방법은 2가지 입니다.

  • {...obj} 처럼 spread operator를 활용
  • Object.assign(obj, target) 메서드를 활용

여기서 한 가지 방법을 더 알게되네요.

const obj = Object.create(
  Object.getPrototypeOf(target),
  Object.getOwnPropertyDescriptors(target) // getOwnPropertyDescriptor와 헷갈리기ㄴㄴ
);`

Pure dictionary

프로토타입을 가지지 않는 객체를 단순객체(pure dictionary)라고 합니다.

const obj = Object.create(null); 

이 객체는 프로토타입을 가지지 않기 때문에 내장메서드를 활용할 수 없습니다.


정리

지금까지 자바스크립트의 프로토타입을 알아봤습니다. 객체, 생성자함수 뿐만아니라 이후에 배울 클래스도 프로토타입을 기반으로 상속을 구현합니다. 이는 뒤에서 자세히 알아보겠습니다.

profile
세계 최고 수준을 향해 달려가는 개발자입니다.

0개의 댓글