this는 카멜레온이다. 함수를 호출할 때 결정된다.

JavaScript를 공부하다 보면 반드시 한 번은 this 때문에 멘붕이 온다. "분명 같은 함수인데 왜 여기선 undefined가 나오지?" 하는 경험, 다들 한 번쯤 있을 것이다. 이 글은 그 혼란을 끝내기 위한 올인원 가이드다.

1. this란 무엇인가


this함수가 실행되는 컨텍스트(Context)를 가리키는 키워드다. 중요한 점은, this의 값은 함수를 어떻게 정의했느냐가 아니라 어떻게 호출했느냐에 의해 결정된다는 것이다.

비유하자면, this는 무대 위의 조명 같다. 조명(this)은 항상 현재 공연 중인 배우(호출한 주체)를 비춘다. 배우가 바뀌면 조명도 따라간다.

const someone = {
  name: "codeman",
  getInfo: function () {
    console.log(this);
  },
};

someone.getInfo();
// 출력 → {name: 'codeman', getInfo: ƒ}
// someone이 호출했으므로 this === someone
const myGetInfo = someone.getInfo;
myGetInfo();
// 출력 → Window {...}
// 전역(window)이 호출했으므로 this === window

someone.getInfo()someone이라는 객체가 호출한 것이고, myGetInfo()는 전역 컨텍스트(브라우저 환경에서는 window)가 호출한 것이다. 함수 자체는 완전히 동일하지만, 누가 호출했냐에 따라 this가 완전히 달라진다.

2. this가 결정되는 4가지 규칙


2-1) 기본 바인딩 (Default Binding)

가장 기본적인 경우로, 아무 객체 없이 단독으로 함수를 호출하면 this는 전역 객체(window)를 가리킨다. strict mode에서는 undefined가 된다.

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

sayHello(); // Window {...}

2-2) 암시적 바인딩 (Implicit Binding)

함수 앞에 점(.)을 통해 객체가 붙어 호출되면, this는 그 객체를 가리킨다.

const obj = {
  name: "zerocho",
  sayName() {
    console.log(this.name);
  },
};

obj.sayName(); // "zerocho"
// obj가 앞에 붙었으므로 this === obj

단, 메서드를 변수에 담아서 꺼내 쓰는 순간 암시적 바인딩은 사라진다. 이를 암시적 바인딩의 손실(Implicit Binding Loss)이라 한다.

const sayN = obj.sayName;
sayN(); // '' (window.name은 빈 문자열)
// 이제 호출 주체는 window이므로 this === window

2-3) new 바인딩 (New Binding)