FEInterview Prep

javascript · high priority

JavaScript 프로토타입과 상속

[[Prototype]] · 프로토타입 체인 · class 의 진짜 정체

intermediate 난이도4시간토스카카오네이버당근배민
시작 전
이해도
매우 낮음

학습 개요

탄생 배경

쉬운 설명

복잡한 개념을 실생활 비유로 설명합니다.

도서관 서가의 청구기호 체인

찾는 책(프로퍼티) 이 내 방(객체) 에 없으면 부모 서가(Prototype) 로 올라갑니다. 거기도 없으면 더 위층(Object.prototype) 으로 가고, 마지막엔 "더 이상 없음(null)" 이라는 종착역에 도달해 undefined 를 돌려받습니다. 책을 "빌려 쓰는" 건(조회) 공유지만, 새 책을 "두는" 건(할당) 내 방에만 생깁니다.

핵심 개념

모든 자바스크립트 객체에는 [[Prototype]] 이라는 **내부 슬롯** 이 있고, 이것은 다른 객체(또는 null) 를 가리킵니다. 프로퍼티 접근 obj.x 는 먼저 obj 자신에서 x 를 찾고, 없으면 [[Prototype]] 이 가리키는 객체에서 찾고, 또 없으면 다시 그 객체의 [[Prototype]] 으로 올라가는 식으로 null 을 만날 때까지 탐색합니다. 이 탐색 경로가 **프로토타입 체인** 입니다.

조회 vs 할당은 체인 처리가 다르다javascript
1const parent = { greet: 'hi' };
2const child = Object.create(parent); // child.[[Prototype]] = parent
3
4// 조회 — 체인을 따라 올라감
5console.log(child.greet); // 'hi' (parent 에서 발견)
6
7// 할당 — 체인을 올라가지 않고 "자기 자신에 생성"
8child.greet = 'hello';
9console.log(child.greet); // 'hello' (child 자신 프로퍼티)
10console.log(parent.greet); // 'hi' (parent 는 그대로)
11
12// hasOwnProperty 로 자신/상속 구분
13console.log(child.hasOwnProperty('greet')); // true

프로토타입 체인 수정 비용

Object.setPrototypeOfobj.__proto__ = 는 **엔진이 해당 객체에 대한 히든 클래스/inline cache 를 무효화** 합니다. V8 문서도 핫 패스에서는 피하라고 명시. 가능하면 Object.create(proto) 로 생성 시점에 프로토타입을 확정하세요.

실무 적용

어떤 상황에서 사용하는가

대규모 앱에서 사용자 입력을 키로 사용하는 캐시 객체가 있는데, 어떤 키로 인해 `.hasOwnProperty` 가 덮어써져 런타임 에러가 발생한다.

어떻게 적용하는가

일반 `{}` 는 Object.prototype 체인에 연결되어 있어 `__proto__`, `constructor`, `hasOwnProperty` 같은 키를 공격자나 사용자가 넣으면 동작이 꼬인다. `Object.create(null)` 또는 `Map` 을 쓰면 체인이 없어 이 문제가 사라지고, `hasOwnProperty` 조회 시엔 항상 `Object.prototype.hasOwnProperty.call(obj, key)` 로 호출한다.

흔한 실수와 안티패턴

  • `obj.hasOwnProperty(key)` 직접 호출 — 키 이름이 hasOwnProperty 면 깨짐. `Object.hasOwn(obj, key)` (ES2022) 또는 `.call` 사용
  • `__proto__` 를 정상 프로퍼티 이름으로 사용 — 구형 브라우저에서 프로토타입으로 해석됨
  • React 클래스 컴포넌트에서 메서드 → this 바인딩 누락 — prototype 메서드의 this 는 호출 방식에 따라 결정
  • class extends Array 한 뒤 `.slice()` 로 반환된 게 서브클래스가 아닌 Array 로 기대 — 실제로는 Symbol.species 로 서브클래스가 반환됨
  • Object.prototype 에 유틸 메서드 추가(monkey patch) — for...in, 라이브러리 코드 전체 오동작

흔한 오해

오해

"자바스크립트 class 는 Java 의 class 와 본질적으로 같다."

교정

런타임 모델은 여전히 프로토타입 체인 — class 는 그 위에 얹은 문법일 뿐.

왜 중요

typeof Class === "function", Class.prototype 이 존재하고 new 시 [[Prototype]] 으로 연결되는 방식이 function 생성자와 동일하다.

오해

"__proto__ 와 prototype 은 같은 것이다."

교정

`__proto__` 는 인스턴스의 `[[Prototype]]` 을 가리키는 legacy 접근자, `.prototype` 은 함수만 가진, 인스턴스의 [[Prototype]] 이 될 객체.

왜 중요

대부분의 객체는 `.prototype` 프로퍼티가 없다 — 오직 "함수" 만 갖는다. 그래서 `([]).prototype === undefined`.

오해

"Object.create(proto) 는 proto 를 얕은 복사한다."

교정

복사가 아니라 새 객체의 [[Prototype]] 으로 proto 를 연결만 한다 — proto 수정은 자식에게 즉시 보인다.

왜 중요

체인은 참조 기반이라 parent 의 프로퍼티 변경은 child 에서 그대로 관찰된다 (shadowing 되지 않은 경우).

면접 질문

중급토스카카오네이버

답변 방향 힌트

인스턴스의 체인(메서드 탐색용) 과 클래스 자체의 체인(static 탐색용) 이 각각 어디로 이어지는지 구분하세요.

반드시 언급할 키워드

  • 인스턴스 → Dog.prototype → Animal.prototype → Object.prototype → null
  • 클래스 객체 자체: Dog → Animal → Function.prototype → Object.prototype → null
  • 그래서 static 메서드는 자식 클래스에서도 탐색으로 발견됨
  • constructor 가 없으면 암묵적으로 `super(...args)` 를 호출하는 constructor 가 생성됨
  • new.target 으로 어떤 클래스가 호출되었는지 확인 가능

예상 꼬리 질문

  • `super.method()` 호출은 프로토타입 체인을 어떻게 탐색하나요?
  • static 메서드를 override 하면 다형성이 동작하나요?

자기 점검

스크롤 올리지 말고 답해보세요. `[[Prototype]]` 과 `.prototype` 의 차이는?

기대 키워드

모든 객체함수체인newObject.getPrototypeOf

자주 하는 오해

"둘 다 같은 것을 다른 이름으로 부르는 것" 이라는 오해가 흔합니다. `[[Prototype]]` 은 모든 객체가 가진 내부 슬롯이고, `.prototype` 은 함수만 갖는 일반 프로퍼티로 "이 함수로 new 해서 만든 객체의 [[Prototype]] 이 될 객체" 입니다.

`class Foo {}` 가 내부적으로 어떤 런타임 객체를 만드는지 한 문장으로?

기대 키워드

함수 객체prototypenewstricttypeof function

자주 하는 오해

class 가 별도의 타입이라고 생각하기 쉽지만 실제로는 typeof Foo === "function" 이고, 내부적으로는 생성자 함수 + Foo.prototype 셋업이 syntactic sugar 로 만들어집니다.

사용자 입력을 키로 쓰는 캐시에 `{}` 를 쓰면 안 되는 이유와 대체제 2가지?

기대 키워드

Object.prototype__proto__pollutionObject.create(null)Map

자주 하는 오해

"동작만 되면 된다" 고 넘어가기 쉽지만, `__proto__`/`constructor`/`hasOwnProperty` 같은 이름의 키가 들어올 때 prototype pollution 으로 런타임 오동작이나 보안 취약점이 된다는 점을 기억해야 합니다.

학습 자료