객체와 프로토타입 (Object and Prototype)
한눈에 보기
JavaScript의 모든 객체는 프로토타입을 내부 링크로 참조하며, 프로토타입 체인을 따라 프로퍼티를 탐색해 상속을 구현한다. prototype과 __proto__의 구분, class 문법, 프로토타입 오염까지 다룬다.
최종 업데이트 2026.09.17
JavaScript의 객체(Object)는 키와 값의 쌍인 프로퍼티(Property)의 집합이며, 모든 객체는 프로토타입(Prototype)이라 불리는 또 다른 객체를 내부 링크로 참조한다. JavaScript는 클래스 기반 상속 대신 이 링크를 따라 프로퍼티를 탐색하는 프로토타입 체인(Prototype Chain)으로 상속을 구현하는 프로토타입 기반 언어다. class 문법 역시 내부적으로는 이 메커니즘 위에서 동작한다.
객체를 만드는 방법
객체는 객체 리터럴, 생성자 함수, Object.create, class 문법으로 만들 수 있다. 어떤 방법을 쓰든 만들어진 객체는 자신의 프로토타입에 대한 내부 슬롯 [[Prototype]]을 가진다. 리터럴로 만든 객체의 프로토타입은 Object.prototype이고, 생성자 함수로 만든 인스턴스의 프로토타입은 그 함수의 prototype 프로퍼티가 가리키는 객체다.
const literal = { name: "kim" }; // 프로토타입은 Object.prototype
function User(name) { this.name = name; }
const u = new User("lee"); // 프로토타입은 User.prototype
const bare = Object.create(null); // 프로토타입이 없는 순수 객체
prototype과 __proto__의 구분
면접에서 가장 많이 혼동하는 지점이 prototype 프로퍼티와 [[Prototype]] 링크의 구분이다. prototype은 생성자로 쓰일 함수만 갖는 프로퍼티로, 그 함수로 만들 인스턴스들의 프로토타입이 될 객체를 가리킨다. 반면 [[Prototype]]은 모든 객체가 갖는 내부 링크이며, 과거에는 __proto__ 접근자로 읽었지만 현재 표준은 Object.getPrototypeOf와 Object.setPrototypeOf 사용을 권장한다.
| 구분 | prototype | [[Prototype]] (__proto__) |
|---|---|---|
| 누가 갖는가 | 생성자 함수와 클래스 | 모든 객체 |
| 무엇을 가리키는가 | 미래 인스턴스들의 프로토타입이 될 객체 | 자신의 부모에 해당하는 프로토타입 객체 |
| 접근 방법 | Func.prototype | Object.getPrototypeOf(obj) |
따라서 new User("lee")로 만든 인스턴스 u에 대해 Object.getPrototypeOf(u) === User.prototype이 성립한다.
프로토타입 체인의 탐색 규칙
객체의 프로퍼티를 읽을 때 JavaScript 엔진은 먼저 객체 자신의 프로퍼티(Own Property)를 확인하고, 없으면 [[Prototype]] 링크를 따라 올라가며 찾는다. 체인의 끝은 Object.prototype이고 그 프로토타입은 null이다. 끝까지 찾지 못하면 undefined가 반환된다. 배열에서 map을 호출할 수 있는 이유도 배열 인스턴스에는 map이 없지만 Array.prototype에 정의되어 있고 체인을 통해 공유되기 때문이다.
const animal = {
eat() { return "먹는다"; }
};
const dog = Object.create(animal);
dog.bark = function () { return "짖는다"; };
dog.bark(); // 자신의 프로퍼티에서 발견
dog.eat(); // animal에서 발견, 체인을 따라 탐색
dog.fly; // undefined, 체인 끝까지 없음
중요한 점은 이것이 복사가 아니라 위임(Delegation)이라는 사실이다. 프로토타입의 메서드는 하나만 존재하고 모든 인스턴스가 공유하므로 메모리 효율이 좋고, 프로토타입을 수정하면 기존 인스턴스에도 즉시 반영된다. 반면 쓰기 연산은 체인을 따라 올라가지 않고 항상 객체 자신에게 프로퍼티를 만들기 때문에, 같은 이름의 프로퍼티가 프로토타입의 것을 가리는 섀도잉(Shadowing)이 일어난다.
생성자 함수에서 class 문법으로
ES2015의 class는 생성자 함수와 프로토타입 조작을 선언적으로 감싼 문법적 설탕(Syntactic Sugar)이다. 클래스 본문에 정의한 메서드는 자동으로 prototype 객체에 놓이고, extends는 인스턴스 체인과 정적 멤버 체인을 함께 연결한다. 다만 class는 new 없이 호출하면 오류가 나고, 클래스 선언은 호이스팅되어도 일시적 사각지대의 적용을 받는 등 일반 함수와 동작이 완전히 같지는 않다.
class Animal {
constructor(name) { this.name = name; }
eat() { return `${this.name}가 먹는다`; }
}
class Dog extends Animal {
bark() { return "멍멍"; }
}
const d = new Dog("초코");
d.eat(); // Animal.prototype에서 위임받아 실행
주의할 점
for...in 반복문은 프로토타입 체인에서 상속된 열거 가능 프로퍼티까지 순회하므로, 객체 자신의 키만 다루려면 Object.hasOwn(obj, key)나 Object.keys를 사용해야 한다. 또한 Object.prototype처럼 널리 공유되는 내장 프로토타입을 수정하는 일은 모든 객체의 동작을 바꾸는 것이므로 피해야 한다. 외부 입력으로 객체 키를 만들 때 __proto__ 같은 키를 그대로 받아들이면 프로토타입 오염(Prototype Pollution) 공격으로 이어질 수 있으므로, 맵(Map)을 쓰거나 Object.create(null)로 만든 객체를 사전 용도로 쓰는 것이 안전하다.
면접에서 이렇게 물어본다
- prototype 프로퍼티와 __proto__의 차이를 정확히 구분해서 설명해 보라.
- 프로토타입 체인의 탐색 과정을 배열의 map 메서드 호출을 예로 들어 설명해 보라.
- class 문법이 문법적 설탕이라고 불리는 이유와 생성자 함수와의 차이점은 무엇인가.
- 프로토타입에 메서드를 정의하는 방식이 메모리 측면에서 유리한 이유를 설명해 보라.
- 프로토타입 오염 공격이 무엇이고 어떻게 방어할 수 있는가.
JavaScript / Python에서 같이 읽기
- 클로저 (Closure)클로저는 함수가 선언된 시점의 렉시컬 환경을 기억해 스코프 밖에서도 변수에 접근하게 하는 JavaScript 특성이다. 동작 원리, 카운터 예시, 데이터 은닉 활용, var와 let의 루프 함정까지 정리한다.
- JavaScript 데이터 타입 (Data Types)JavaScript 데이터 타입은 원시 타입 7가지와 객체 타입으로 나뉜다. 값 복사와 참조 복사의 차이, typeof의 함정, 암묵적 타입 변환과 ===, Truthy와 Falsy까지 핵심을 정리한다.
- ES2015+ 핵심 문법 (ES6 and Beyond)ES2015는 let과 const, 화살표 함수, 클래스, 프로미스, 모듈 등 현대 JavaScript의 근간을 도입한 표준이다. 이후 async/await와 옵셔널 체이닝까지 이어지는 핵심 문법을 정리한다.
- 파이썬 자동화 라이브러리 (Python Automation)파이썬 자동화 라이브러리는 마우스와 키보드 입력, 화면 인식, 브라우저 조작을 코드로 수행하는 도구다. PyAutoGUI, Selenium, pywinauto의 접근 방식 차이와 선택 기준, 주의점을 정리한다.
이 개념, 내 코드에서는 어떻게 물어볼까요
데브핏(DevFit)에 채용공고 URL을 붙여 넣고 레포지토리를 연결하면, 내가 쓴 커밋에서 예상 질문과 어필 포인트를 만듭니다. 하루 10회까지 무료입니다. 합불 판정이나 지원자 랭킹은 만들지 않고, 최종 판단은 사람이 합니다.
공고 넣고 시작하기