전체 목록
JavaScriptMedium#121

this 바인딩은 호출 방식에 따라 어떻게 달라지나요?

#JS#this#함수#실행컨텍스트

답변 포인트

호출 방식과 화살표 함수의 차이를 기준으로 정의, 장점, 한계, 예시를 함께 설명해보세요.

정답 및 해설

빠른 요약

this는 함수가 선언된 위치보다 호출 방식에 따라 결정되는 경우가 많습니다. 일반 함수, 메서드, 생성자, call/apply/bind 호출에서 값이 달라지고, 화살표 함수는 상위 스코프의 this를 렉시컬하게 사용합니다.

this는 함수가 선언된 위치보다 호출 방식에 따라 결정되는 경우가 많습니다. 일반 함수, 메서드, 생성자, call/apply/bind 호출에서 값이 달라지고, 화살표 함수는 상위 스코프의 this를 렉시컬하게 사용합니다.

핵심 개념

핵심 기준은 호출 방식과 화살표 함수의 차이입니다. 이 개념은 단순한 용어가 아니라, 실제 코드나 시스템에서 반복적으로 생기는 문제를 다루기 위해 등장했습니다.

JavaScript는 실행 문맥, 비동기 흐름, 참조 관계가 코드 동작에 직접 영향을 주는 언어입니다. 그래서 문법을 외우는 것보다 값이 언제 결정되고 어떤 순서로 실행되는지 이해하는 것이 중요합니다.

동작 흐름

  1. 먼저 어떤 문제가 있는지 확인합니다.
  2. 이 개념이 그 문제를 어떤 기준으로 나누거나 해결하는지 봅니다.
  3. 실제 코드에서는 입력, 상태, 실행 순서, 비용이 어떻게 바뀌는지 확인합니다.
  4. 마지막으로 한계와 부작용을 함께 점검합니다.

실제 예시

JavaScript
const user = {
  name: "Ada",
  sayHi() {
    console.log(this.name);
  },
};

user.sayHi();        // "Ada" - 메서드 호출
const fn = user.sayHi;
fn();                // strict mode에서는 this가 undefined

const fixed = user.sayHi.bind(user);
fixed();             // "Ada"

같은 함수라도 호출 형태가 바뀌면 this가 달라집니다. 그래서 메서드를 콜백으로 넘길 때는 bind나 화살표 함수 사용 여부를 신중히 봐야 합니다.

실무에서 주의할 점

  • 암묵적 변환이나 실행 문맥에 기대면 작은 리팩터링에도 동작이 달라질 수 있습니다.
  • 비동기 코드에서는 실행 순서와 에러 전파 경로를 반드시 확인해야 합니다.
  • 브라우저 이벤트나 타이머를 사용했다면 정리(cleanup) 시점을 놓치지 않는 것이 좋습니다.

함께 연결해서 보면 좋은 키워드

JS, this, 함수, 실행컨텍스트

정리

한 줄로 정리하면, this는 함수가 선언된 위치보다 호출 방식에 따라 결정되는 경우가 많습니다. 일반 함수, 메서드, 생성자, call/apply/bind 호출에서 값이 달라지고, 화살표 함수는 상위 스코프의 this를 렉시컬하게 사용합니다. 실무에서는 개념을 적용하는 조건과 적용하지 않았을 때 생기는 문제까지 함께 이해하는 것이 중요합니다.

호출 방식별 this 결정

JavaScript의 this는 함수가 어디에 선언됐는지가 아니라 어떻게 호출됐는지에 따라 결정됩니다. 단, 화살표 함수는 자신만의 this를 만들지 않고 바깥 렉시컬 스코프의 this를 사용합니다.

JavaScript
const user = {
  name: 'Kim',
  say() { console.log(this.name); },
};

user.say(); // Kim: 메서드 호출 → this는 user
const fn = user.say;
fn(); // strict mode에서는 undefined

대표 규칙

호출 방식this
obj.method()obj
fn()strict mode: undefined, non-strict: 전역 객체
new Fn()새로 생성된 인스턴스
fn.call(obj)명시한 obj
화살표 함수선언 위치의 바깥 this

실무에서 자주 나는 버그

JavaScript
class Timer {
  seconds = 0;

  start() {
    setInterval(function () {
      this.seconds++; // ❌ this가 Timer 인스턴스가 아님
    }, 1000);
  }
}
JavaScript
class Timer {
  seconds = 0;

  start() {
    setInterval(() => {
      this.seconds++; // ✅ 화살표 함수가 바깥 this를 캡처
    }, 1000);
  }
}

React 클래스 컴포넌트의 이벤트 핸들러에서 bind가 필요했던 이유도 같은 문제입니다. 함수 참조만 넘기면 호출 주체가 사라지기 때문입니다.

관련 질문

같은 카테고리/태그 기준