학습 공간 개념 · 판단 · 실험

Frontend Performance Lab

JavaScript

프로토타입, 생성자, 클래스와 this

객체가 프로토타입 체인을 따라 프로퍼티를 찾는 규칙과, 함수가 호출되는 방식에 따라 this가 결정되는 규칙을 구분해 이해합니다.

이럴 때 필요해요

메서드를 콜백으로 전달할 때 this가 사라지는 버그와 클래스·상속 구조에 대한 오해를 막을 수 있습니다.

어떻게 동작하나요?

배열을 하나 만든 뒤 직접 정의한 적 없는 arr.map()이나 obj.toString()을 호출해도 정상적으로 동작하는 이유는 무엇일까요? 객체에서 특정 프로퍼티를 찾을 때 그 객체 자신에게 없으면, 내부의 숨겨진 연결인 [[Prototype]]이 가리키는 상위 객체로 올라가며 이름을 찾기 때문입니다. 이를 프로토타입 체인(Prototype Chain)이라고 합니다. 생성자 함수를 new로 호출하면 새 객체가 만들어지고, 그 객체의 내부 [[Prototype]]이 생성자 함수의 prototype 프로퍼티에 자동으로 연결됩니다.

반면 일반 함수 안의 this는 상속 연결이나 함수가 작성된 위치가 아니라, '함수를 어떻게 호출했는가'에 따라 매번 달라집니다. counter.increment()처럼 객체를 통해 호출하면 this가 counter를 가리키지만, 그 메서드를 변수에 담아 단독으로 호출하면 원래 객체와의 연결이 끊어져 엄격 모드에서는 this가 undefined가 됩니다. 이때 call과 apply는 this와 인자를 직접 지정해 함수를 즉시 실행하고, bind는 원하는 객체를 this로 고정한 새 함수를 반환합니다. 화살표 함수는 자체적인 this를 만들지 않고 바깥 스코프의 this를 그대로 물려받습니다.

ES2015의 class 문법은 이러한 프로토타입 기반 객체 모델 위에서 생성자(constructor), 인스턴스·정적 메서드, 필드, extends 상속을 깔끔하게 선언하도록 도와줍니다. 단순히 기존 생성자 함수의 겉모양만 바꾼 것이 아니라, new 없이 호출할 수 없고 본문이 자동으로 엄격 모드(strict mode)로 동작하며 #필드를 통한 런타임 private 캡슐화도 지원합니다.

코드 예제

동작을 설명하는 읽기 전용 예제입니다.

example.js
class Counter {
  value = 0;
  increment() { return ++this.value; }
}
const counter = new Counter();
const run = counter.increment.bind(counter);
console.log(run()); // 1
javascript · 읽기 전용7줄

bind로 수신자(counter)를 고정했기 때문에 메서드를 별도 변수에 담아 호출하거나 콜백으로 전달해도 항상 같은 객체를 안전하게 갱신합니다.

자주 헷갈리는 포인트

  • 화살표 함수의 this는 생성 시점의 바깥 스코프로 고정되므로 call, apply, bind로도 바꿀 수 없습니다.
  • 이미 생성된 객체의 프로토타입 연결을 런타임에 임의로 바꾸는 것은 엔진 최적화를 해치므로 권장하지 않습니다.

내 말로 설명해 보기

객체의 메서드를 obj.method()로 직접 호출할 때와 변수에 담아 호출할 때 this는 어떻게 달라질까요?

함께 읽으면 좋은 개념

관련 면접 질문 5개

생성자와 new 호출은 객체를 어떻게 만드나요?

생성자는 new 연산자와 함께 호출해 새 인스턴스 객체를 만드는 함수입니다. 함수를 new로 호출하면 먼저 빈 객체가 생성되고, 그 객체의 내부 프로토타입이 생성자 함수의 prototype 프로퍼티에 연결된 뒤 생성자 본문이 그 객체를 this로 삼아 실행됩니다. 만약 생성자에서 별도의 객체를 명시적으로 반환하지 않으면 방금 초기화된 새 객체가 최종 반환값이 되며, class 문법의 constructor도 같은 프로토타입 기반 위에서 동작하지만 반드시 new와 함께 호출해야 합니다.

꼬리질문과 참고자료 →

this는 어떻게 정해지며 call·apply·bind는 무엇이 다른가요?

일반 함수의 this는 함수가 정의된 위치가 아니라 어떻게 호출되었는지에 따라 결정됩니다. 예를 들어 obj.method()처럼 호출하면 this가 obj를 가리키지만, 그 메서드를 변수에 담아 단독으로 호출하면 기존 객체와의 연결을 잃게 됩니다. 이때 call과 apply는 원하는 this와 인자를 직접 지정해 함수를 즉시 실행하는 메서드이고, bind는 지정한 this와 일부 인자를 고정한 새로운 함수를 만들어 반환합니다. 반면 화살표 함수는 자신만의 this를 바인딩하지 않고 바깥 스코프의 this를 그대로 사용합니다.

꼬리질문과 참고자료 →

프로토타입 체인은 프로퍼티를 어떻게 찾나요?

객체에서 특정 프로퍼티나 메서드를 읽을 때 먼저 그 객체가 직접 가진 고유(own) 프로퍼티를 확인하고, 없으면 객체 내부의 [[Prototype]] 연결이 가리키는 상위 객체로 따라 올라가며 탐색합니다. 이렇게 최상위의 null에 도달할 때까지 연결을 따라 이름을 찾는 구조를 프로토타입 체인이라고 합니다. ES2015의 class 문법으로 작성한 인스턴스 메서드 역시 각 인스턴스에 복사되는 것이 아니라 클래스의 prototype 객체에 올라가 이 체인을 통해 공유됩니다.

꼬리질문과 참고자료 →
나머지 질문 2개

공식 참고 자료

← JavaScript