모든 객체는 연결되어 있다
JavaScript에서 객체를 하나 만들어봅시다:
const obj = { a: 1 };
obj.toString(); // "[object Object]", 어디서 왔을까?obj에는 toString이 없습니다. 그런데 호출이 됩니다. 이것이 프로토타입 (prototype) 의 힘입니다.
모든 JavaScript 객체는 다른 객체와 숨겨진 링크로 연결되어 있습니다. 이 링크를 [[Prototype]] 이라는 내부 슬롯이 관리합니다.
[[Prototype]] 내부 슬롯
const animal = {
eats: true,
walk() { return "walking"; }
};
const rabbit = {
jumps: true,
__proto__: animal // rabbit의 [[Prototype]]을 animal로 설정
};rabbit의 [[Prototype]]이 animal을 가리킵니다. rabbit에서 속성을 찾을 때 없으면, 엔진은 [[Prototype]]을 따라 animal에서 찾습니다.
접근 방법
[[Prototype]]은 내부 슬롯이라 직접 접근할 수 없습니다. 세 가지 방법으로 접근합니다.
__proto__ (레거시)
const rabbit = {};
rabbit.__proto__ = animal;
console.log(rabbit.__proto__ === animal); // true__proto__는 Object.prototype의 접근자 프로퍼티입니다. getter/setter로 [[Prototype]]을 읽고 씁니다. 레거시 기능이지만, ECMAScript 명세의 Annex B에 공식 포함되어 있습니다. 표준 대안인 Object.getPrototypeOf를 사용하는 것이 권장됩니다.
Object.getPrototypeOf / Object.setPrototypeOf (표준)
const proto = Object.getPrototypeOf(rabbit);
console.log(proto === animal); // true
Object.setPrototypeOf(rabbit, anotherAnimal);표준 방법입니다. 코드에서는 이것을 사용하세요.
Object.create (생성 시 설정)
const rabbit = Object.create(animal);
rabbit.jumps = true;
// 위는 아래와 동일합니다
const rabbit = { jumps: true, __proto__: animal };Object.create(proto)는 [[Prototype]]이 proto인 새 객체를 만듭니다.
읽기와 쓰기의 차이
프로토타입은 읽기 전용으로 공유됩니다. 속성을 읽을 때는 체인을 따라 올라가지만, 쓸 때 는 일반적으로 객체 자신에 씁니다. 단, 프로토타입에 같은 이름의 writable: false 프로퍼티나 setter가 있으면 예외입니다 (다음 글에서 자세히 다룹니다).
const animal = { eats: true };
const rabbit = { __proto__: animal };
// 읽기, 체인을 올라감
console.log(rabbit.eats); // true (animal에서 읽음)
// 쓰기, rabbit에 직접 추가
rabbit.eats = false;
console.log(rabbit.eats); // false (rabbit 자체)
console.log(animal.eats); // true (animal은 변하지 않음)이것을 프로퍼티 섀도잉 (property shadowing) 이라고 합니다. rabbit.eats가 animal.eats를 "가립니다".
hasOwnProperty
속성이 객체 자체에 있는지, 프로토타입에서 상속된 것인지 구분하려면:
const animal = { eats: true };
const rabbit = { jumps: true, __proto__: animal };
rabbit.hasOwnProperty("jumps"); // true , 자체 속성
rabbit.hasOwnProperty("eats"); // false, 상속된 속성for...in은 상속된 속성까지 순회하지만, Object.keys()는 자체 속성만 반환합니다.
for (const key in rabbit) {
console.log(key);
// "jumps" (자체)
// "eats" (상속)
}
Object.keys(rabbit);
// ["jumps"] (자체만)다음 단계
프로토타입의 기본 개념을 이해했습니다. 다음 글에서는 프로토타입이 체인으로 연결되어 있을 때 속성 탐색이 어떻게 동작하는지, 프로토타입 체인 을 살펴보겠습니다.