[Javascript] Prototype Chain
JS Prototype, JS Prototype Chain, Prototype, 프로토타입, 프로토타입 체인, prototypal inheritance, prototype chain
정의
JavaScript 의 모든 객체는 [[Prototype]] (내부 슬롯) 을 가진다. 속성 lookup 시 자신에게 없으면 prototype chain 을 따라 올라가며 검색.
const animal = { eats: true };
const dog = Object.create(animal);
dog.barks = true;
dog.barks // true (own)
dog.eats // true (prototype 에서)
접근
Object.getPrototypeOf(obj) // [[Prototype]] 반환
Object.setPrototypeOf(obj, p) // 변경 (성능 주의)
obj.__proto__ // 비표준 getter (피하기)
함수의 prototype
함수는 prototype property 를 가진다 (객체).
function Foo() {}
Foo.prototype // {} (객체)
Foo.prototype.constructor // Foo
const obj = new Foo();
Object.getPrototypeOf(obj) === Foo.prototype // true
obj.__proto__ === Foo.prototype // true
new Foo() 시 새 객체의 [[Prototype]] 이 Foo.prototype 으로 설정.
class 와의 관계
class Animal {
eat() { return 'eating'; }
}
class Dog extends Animal {
bark() { return 'woof'; }
}
const d = new Dog();
d.bark() // 'woof' (own)
d.eat() // 'eating' (prototype chain)
내부적으로 같은 prototype chain.
d → Dog.prototype → Animal.prototype → Object.prototype → null
prototype chain 의 끝
Object.getPrototypeOf({}) === Object.prototype // true
Object.getPrototypeOf(Object.prototype) === null // true
const clean = Object.create(null);
Object.getPrototypeOf(clean) // null
Object.create(null) 은 prototype 없는 진짜 깨끗한 객체 (사전처럼 사용).
속성 lookup 순서
const grandparent = { x: 1 };
const parent = Object.create(grandparent);
parent.y = 2;
const child = Object.create(parent);
child.z = 3;
child.z // 3 (own)
child.y // 2 (parent)
child.x // 1 (grandparent)
child.w // undefined (chain 끝까지 못 찾음)
자신 → prototype → … → null 까지 탐색.
속성 검색 시점
- 읽기 : chain 전체 검색
- 쓰기 : 자기 자신에 추가 (chain 변경 안 함)
const parent = { x: 1 };
const child = Object.create(parent);
child.x // 1 (parent 에서)
child.x = 2;
child.x // 2 (own, parent 의 x 는 1 그대로)
parent.x // 1
constructor
function Foo() {}
const obj = new Foo();
obj.constructor === Foo // true (Foo.prototype.constructor)
[].constructor === Array // true
'hi'.constructor === String // true (auto-boxing)
Object 메서드들
| 메서드 | 의미 |
|---|---|
Object.hasOwn(obj, key) | own property 검사 (Object.hasOwnProperty 대체) |
obj.hasOwnProperty(key) | 같음 (옛 방식) |
key in obj | chain 포함 포함 검사 |
Object.keys(obj) | own enumerable string 키 |
Object.getOwnPropertyNames(obj) | own non-enumerable 포함 |
Reflect.ownKeys(obj) | 모든 own (Symbol 포함) |
const parent = { x: 1 };
const child = Object.create(parent);
child.y = 2;
'y' in child // true
'x' in child // true (chain)
Object.hasOwn(child, 'y') // true
Object.hasOwn(child, 'x') // false
Object.keys(child) // ['y']
class 의 static vs instance
class Foo {
static staticMethod() { return 'static'; }
instanceMethod() { return 'instance'; }
}
Foo.staticMethod() // ✓ (Foo 자체에 있음)
new Foo().staticMethod() // ❌ (instance 의 prototype 에 없음)
new Foo().instanceMethod() // ✓ (Foo.prototype 에 있음)
Foo.instanceMethod() // ❌
함정
1. proto vs prototype
// instance → __proto__ 또는 getPrototypeOf
// function → prototype
function Foo() {}
const f = new Foo();
f.__proto__ === Foo.prototype // true
f.prototype // undefined
2. setPrototypeOf 의 성능
엔진이 prototype chain 을 캐시 / 최적화. 변경하면 deoptimization. 가능하면 Object.create 로 처음부터.
3. arrow function 에는 prototype 없음
const arrow = () => {};
arrow.prototype // undefined
new arrow() // ❌ TypeError
생성자로 사용 불가.
4. delete 후 chain 검색
const parent = { x: 1 };
const child = Object.create(parent);
child.x = 2;
delete child.x;
child.x // 1 (parent 의 x 가 다시 보임)
참고
이 글의 용어 (3개)
- [Javascript] Classjavascript
- 정의 ES6 는 prototype chain 위의 문법 설탕. C++/Java 스타일 OOP 와 닮았지만 내부는 . 구조 상속 super 의 의미 - : 부모 constructo…
- [Javascript] Lexical Environmentjavascript
- 정의 Lexical Environment (어휘적 환경) 는 ECMAScript 명세 (§9.1) 가 정의한 내부 객체. 함수가 호출될 때마다 새로 만들어지며, 이 호출의 변수들…
- [Javascript] Objectjavascript
- 정의 JavaScript 의 는 key-value 쌍의 컬렉션. 거의 모든 non-primitive 값이 객체. 함수, 배열, 정규식도 객체. 생성 접근 수정 / 삭제 Objec…
💬 댓글