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

this 의 정체 — 4가지 호출 방식

함수가 어떻게 호출되느냐에 따라 this 가 4가지로 결정됨.

고급읽는 시간 7분2026-05-17
같은 함수가 호출 방식에 따라 this 가 달라지는 4가지 도식

JS 의 this 는 처음 보면 마법 같습니다 — 같은 함수가 어디서 호출되느냐에 따라 가리키는 것이 바뀝니다. 사실 규칙은 단 4가지. 22편은 이 규칙과 화살표 함수의 예외, bind/call/apply 의 정확한 차이까지.

핵심 — this 는 "호출 방식" 으로 결정

한 줄. this 는 함수가 "정의된 위치" 가 아니라 "호출된 방식" 으로 결정됩니다. 같은 함수라도 어떻게 부르냐에 따라 4가지 모양 중 하나.

① 메서드 호출 — obj.fn()

const user = {
  name: "준성",
  greet() {
    return `Hi, ${this.name}`;
  }
};

user.greet();   // "Hi, 준성" — this = user

점(.) 앞이 this. 가장 직관적인 경우.

② 일반 함수 호출 — fn()

function show() {
  console.log(this);
}

show();   // 브라우저: window, Node: globalThis
          // strict mode: undefined

strict mode 차이. 일반 모드에서 this = 글로벌 객체. strict mode 에서는 undefined. ESM 파일은 자동으로 strict — 모듈에서는 거의 항상 undefined.

③ 생성자 호출 — new Fn()

function User(name) {
  this.name = name;   // this = 새로 생성될 객체
}

const u = new User("준성");
u.name;   // "준성"

// 클래스도 마찬가지
class User2 {
  constructor(name) { this.name = name; }
}

④ 명시 호출 — call · apply · bind

function greet(greeting) {
  return `${greeting}, ${this.name}`;
}

const user = { name: "준성" };

// call — this + 인자들 (콤마로)
greet.call(user, "Hi");      // "Hi, 준성"

// apply — this + 인자 배열
greet.apply(user, ["Hi"]);   // "Hi, 준성"

// bind — this 를 고정한 새 함수 반환
const greetUser = greet.bind(user);
greetUser("Hi");             // "Hi, 준성"
greetUser("Hello");          // "Hello, 준성"

this 잃는 함정 — 18편 다시

class Counter {
  count = 0;
  increment() {
    this.count++;
  }
}

const c = new Counter();
c.increment();     // OK

// 메서드를 변수에 → 점(.) 분리
const fn = c.increment;
fn();              // ❌ TypeError — this 가 undefined (strict)

// 콜백으로 넘길 때
setTimeout(c.increment, 1000);   // ❌ this 잃음
btn.addEventListener("click", c.increment);   // ❌

// 해결
setTimeout(c.increment.bind(c), 1000);   // ✅ bind
setTimeout(() => c.increment(), 1000);   // ✅ 화살표 wrap

// 또는 클래스 필드에 화살표 (this 고정)
class Counter {
  count = 0;
  increment = () => { this.count++; };
}

화살표 함수의 this — 렉시컬

// 일반 함수 — 호출 방식 따라
const obj = {
  name: "준성",
  fn1: function () {
    return this.name;          // obj 의 메서드 호출 → this = obj
  },
  fn2: () => {
    return this.name;          // 화살표 — 주변 스코프의 this (전역)
  }
};

obj.fn1();   // "준성"
obj.fn2();   // undefined 또는 다른 것

// 화살표는 자기 this 가 없음 — 만들어진 곳의 this 그대로 사용
class App {
  name = "준성";
  setup() {
    setTimeout(() => {
      console.log(this.name);   // ✅ "준성" — setup 의 this 그대로
    }, 100);

    // 일반 함수면?
    setTimeout(function () {
      console.log(this.name);   // ❌ setTimeout 이 호출하니까 this = global
    }, 100);
  }
}

화살표가 콜백에 강한 이유. 일반 함수는 호출 방식에 따라 this 가 바뀜 — 콜백으로 넘기면 잃기 쉬움. 화살표는 만들어진 곳의 this 를 영구히 고정. React·이벤트 핸들러에서 자연스러운 패턴.

this 결정 우선순위 — 한 표

우선호출 방식this
1 (최고)화살표 함수렉시컬 (호출 무관)
2new Fn()새 객체
3fn.call/apply/bind(obj)obj
4obj.fn()obj
5 (최저)fn()strict: undefined / 일반: 전역

실전 — 메서드를 콜백으로 안전하게

// React 클래스 컴포넌트 시절 (역사)
class Btn extends React.Component {
  // 생성자에서 bind
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() { ... }
  render() {
    return <button onClick={this.handleClick}>Click</button>;
  }
}

// 또는 화살표 필드 (현대)
class Btn extends React.Component {
  handleClick = () => { ... };
  render() {
    return <button onClick={this.handleClick}>Click</button>;
  }
}

// 또는 인라인 화살표
<button onClick={() => this.handleClick()}>Click</button>

// 함수형 컴포넌트는 클래스 자체 안 써서 이 문제 없음

전역 객체 — globalThis

// 환경마다 전역 객체 이름이 달랐음
// 브라우저: window
// Node: global
// Web Worker: self
// 통합: globalThis (ES2020+)

globalThis.window === window;   // true (브라우저)
globalThis === global;          // true (Node)

한 줄 가이드

  • 이벤트 핸들러·콜백 → 화살표 또는 bind.
  • 클래스 메서드를 변수로 빼면 this 잃음 — 분리 전 bind.
  • 일반 함수의 this 는 strict 면 undefined. 가능하면 의존 안 하기.
  • 화살표 함수는 new·call/apply 영향 안 받음.
  • TS 면 noImplicitThis(18편) 가 미스 잡아줌.

23편 — 프로토타입 체인

class 뒤에 숨은 진짜. Object.create·__proto__·prototype 의 차이.

📚 쉽게 배우는 자바스크립트 교재
이전: 21편 클로저 · 현재: 22편 (고급) · 다음 → 23편 프로토타입 · 진행: 22/26

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