자바스크립트 교재 · 23편 / 26편

프로토타입 체인 — class 뒤에 숨은 진짜

class 가 사실은 프로토타입의 옷. __proto__ vs prototype.

고급읽는 시간 7분2026-05-17
프로토타입 체인이 객체에서 부모로 거슬러 올라가는 화살표 도식

18편의 class 는 사실 프로토타입 위의 문법적 설탕입니다. JS 의 진짜 객체 모델은 클래스 기반이 아니라 프로토타입 기반 — 객체가 다른 객체를 상속받습니다. 23편은 그 메커니즘을 직접 들여다봅니다.

한 줄 정의

프로토타입 체인. 모든 객체는 다른 객체(=프로토타입) 를 가리키는 내부 링크 [[Prototype]] 를 가짐. 속성·메서드를 찾을 때 자기에게 없으면 그 링크를 따라 올라감 → 거기도 없으면 또 위로 → null 까지.

__proto__ vs prototype — 헷갈리는 한 쌍

function Animal(name) {
  this.name = name;
}
Animal.prototype.speak = function () {
  return `${this.name} 소리`;
};

const dog = new Animal("초코");

// __proto__ : 객체의 "내 부모" 링크 (실제 [[Prototype]])
dog.__proto__ === Animal.prototype;   // true

// prototype : 함수(생성자) 의 "내가 만들 인스턴스의 부모" 설정
Animal.prototype.speak;
dog.speak();                          // "초코 소리" — 자기엔 없지만 prototype 에서 찾음

이름이 헷갈리는 이유.obj.__proto__ — 모든 객체에 있는 "부모" 링크. 이젠 Object.getPrototypeOf(obj) 권장. ② Fn.prototype — 함수(생성자) 한정. new Fn() 으로 만든 인스턴스의 부모가 됨. 둘은 다른 개념인데 둘 다 "prototype" 글자가 들어있어 헷갈림.

체인 따라 검색

const dog = new Animal("초코");

// dog.speak() 를 부를 때 JS 의 검색
// 1. dog 자체에 speak? 없음
// 2. dog.__proto__ (= Animal.prototype) 에 speak? 있음 → 호출
// 3. (없었다면) Animal.prototype.__proto__ (= Object.prototype) 에서 검색
// 4. (없었다면) Object.prototype.__proto__ === null → undefined

Object.create — 프로토타입 직접 지정

const animal = {
  speak() { return `${this.name} 소리`; },
};

// animal 을 프로토타입으로 갖는 새 객체
const dog = Object.create(animal);
dog.name = "초코";
dog.speak();   // "초코 소리"

Object.getPrototypeOf(dog) === animal;   // true

// "프로토타입 없는" 깨끗한 객체 (사전형 용도)
const map = Object.create(null);
map.key = "value";
map.toString;   // undefined — Object.prototype 안 상속 → 키 충돌 위험 없음

class 와 프로토타입 — 같은 것

// class 문법
class Animal {
  constructor(name) { this.name = name; }
  speak() { return `${this.name} 소리`; }
}

// 위와 동일한 옛 함수 패턴
function Animal(name) {
  this.name = name;
}
Animal.prototype.speak = function () {
  return `${this.name} 소리`;
};

// 인스턴스 만들기도 같음
const d = new Animal("초코");
d.__proto__ === Animal.prototype;   // true

extends 의 실체 — 프로토타입 체인 연결

class Dog extends Animal {
  bark() { return `${this.name} 짖기!`; }
}

const d = new Dog("초코");

// 체인: d → Dog.prototype → Animal.prototype → Object.prototype → null
d.bark();   // Dog.prototype.bark
d.speak();  // Animal.prototype.speak (한 단계 위)

Object.getPrototypeOf(Dog.prototype) === Animal.prototype;   // true

instanceof 동작 원리

// instanceof 는 프로토타입 체인을 따라 올라가며 검사
d instanceof Dog;        // d.__proto__ === Dog.prototype → true
d instanceof Animal;     // d.__proto__.__proto__ === Animal.prototype → true
d instanceof Object;     // 더 위로 거슬러 → true

// 직접 구현
function isInstanceOf(obj, Ctor) {
  let proto = Object.getPrototypeOf(obj);
  while (proto) {
    if (proto === Ctor.prototype) return true;
    proto = Object.getPrototypeOf(proto);
  }
  return false;
}

왜 인스턴스 메서드가 메모리 한 번만 — 프로토타입 덕

class User {
  constructor(name) { this.name = name; }
  greet() { ... }     // ← 인스턴스 백만 개여도 메서드 1개 (User.prototype 에)
}

// 비교: 클로저로 만들면 인스턴스마다 함수 복사
function makeUser(name) {
  return {
    name,
    greet() { ... },  // ← 매 호출마다 새 함수 객체
  };
}

클래스가 클로저보다 메모리 효율. 메서드가 인스턴스가 아닌 prototype 에 한 번만 저장. 인스턴스 N 개여도 메서드는 1개. 그래서 대량 인스턴스 — 클래스 권장.

프로토타입 오염 — 보안 함정

// 사용자 입력으로 Object.prototype 을 오염시키면 모든 객체가 영향
const malicious = JSON.parse('{"__proto__": {"isAdmin": true}}');
Object.assign({}, malicious);   // 라이브러리에 따라 위험

const x = {};
x.isAdmin;   // true (?) — 오염됐다면

// 방어
// 1. Object.create(null) 로 부모 없는 객체 사용
// 2. JSON.parse 후 직접 검증
// 3. lodash 등의 deep merge 는 옛 버전이 취약 — 최신 버전 사용

prototype pollution. 2018~2019년 lodash·jQuery 등에서 발견됐던 큰 취약점 유형. 사용자 입력을 __proto__·constructor 같은 키로 머지하면 글로벌 객체 모양이 바뀜. 안전한 라이브러리·검증 필수.

한 표 — 프로토타입 vs 클래스

개념옛 (함수 + prototype)현대 (class)
생성자function User() { }class User { constructor() { } }
메서드 추가User.prototype.fn = ...class 안 fn() { }
상속Child.prototype = Object.create(Parent.prototype)extends Parent
정적User.static = ...static fn() { }
진짜 private불가 (관습 _ )#field (ES2022)

한 줄 결론

  • 모든 객체는 부모([[Prototype]]) 가 있고, 검색은 체인을 따라 위로.
  • class 는 prototype 의 깔끔한 문법.
  • extends 는 prototype 체인 연결.
  • 메서드는 prototype 에 — 메모리 효율.
  • Object.create(null) — 부모 없는 사전형에 유용.
  • __proto__ 직접 조작 피하기 — Object.getPrototypeOf·Object.setPrototypeOf 사용.

24편 — 이터레이터·제너레이터

function*·yield·Symbol.iterator. for...of 의 내부 동작.

📚 쉽게 배우는 자바스크립트 교재
이전: 22편 this · 현재: 23편 (고급) · 다음 → 24편 이터레이터 · 진행: 23/26

© 2026 주나이테크(주) @JUNAITECH