this를 알려면 우선 context가 무엇인지 알아야한다.
간단하게 context란 this가 가리키는 객체라고 할 수 있다.

기본 바인딩 (전역객체)

console.log(this); // window

function func() {
  console.log(this); // window
}

해당 코드를 출력해보면 window 라고 뜨는 것을 알 수 있다. this는 기본적으로 전역 스코프와 전역 스코프에서 생성된 함수에서는 전역 객체(window)를 context로 가지고 있다.

또한 this를 이해하기 위해서 변수를 선언하는 것은 전역 객체에 property를 등록하는 것과 같다는 것을 알아야한다.
무슨 말이냐하면 var a = 1은 window.a = 1 과 같다는 말이다. 이 말을 생각하면서 아래의 코드를 보자.

  var a = 10;
  console.loa(this.a); // 10
  
  function getThis() {
    this.variable1 = "ab"; // 전역 변수로 선언해주는 것과 같다.
    console.log(this); // window
  }
  
  console.log(this.variable1); // undefined
  console.log(this.variable2); // undefined
  
  this.variable2 = "cd";
  
  console.log(this.variable1); // undefined
  console.log(this.variable2); // cd
  
  getThis();
  
  console.log(this.variable1); // ab
  console.log(this.variable2); // cd

getThis가 실행되면서 전연 객체에 variable1: “ab”를 등록해주었으므로 마지막 console에 this.variable1이 “ab”로 찍힐 수 있는 것이다.

암시적 바인딩

전역 스코프가 아니라 객체에서 선언된 함수에서 this를 호출하면 어떻게 될까?
어떤 객체의 property를 통해 함수가 호출되면 그 객체가 this의 context가 된다.

var a = 10;

function outFunc() {
  console.log(this.a);
}

var obj = {
  a: 20,
  func1: outFunc,
  func2: function() {
    console.log(this.a);
  }
};

obj.func1(); // 20
obj.func2(); // 20

this.variable1 = obj.func1; // => window.variable1 = obj.func1
this.variable2 = obj.func2; // => window.variable2 = obj.func2
this.variable1(); // 10
this.variable2(); // 10

outFunc이 생성된 곳은 전역 스코프이나 호출은 객체인 obj의 property로써 호출되었기 때문에 obj.func1()과 obj.func2()에서 this는 obj를 가르키게 된다. 그러나 this.variable1()과 this.variable2()는 전역 스코프에서 this인 window의 property로 등록시킨 후 호출되었기 때문에 this는 window를 가르키게 된다.

명시적 바인딩

그렇다면 함수가 호출되는 곳이 아닌 다른 객체를 this로 지정해야 한다면 어떻게 해야할까?
그럴 때 사용하는 메서드 3가지가 있다. call, apply, bind이다. 같은 기능을 하는데 왜 3가지나 메서드가 있는지 의문이지만 문법이 다르니 상황상 편한 메서드를 사용하도록 하자.

  • call
    • 문법: 문법: func.call(thisArg[, arg1[, arg2[, …]]])
      • thisArg: func 호출에 제공되는 this의 값
      • arg1, arg2, …: func에 호출되어야 하는 인수
    • this 와 arguments 를 매개로 호출된 함수의 결과를 반환한다.
  • apply
    • 문법: func.apply(thisArg, [argsArray])
    • thisArg: func 호출에 제공되는 this의 값
    • argsArray
      • func에 호출되어야 하는 인수를 지정하는 유사 배열 객체
      • 함수에 제공된 인수가 없을 경우 null 또는 undefined이다.
    • this 와 arguments 를 매개로 호출된 함수의 결과를 반환한다.
    • call()과 다르게 apply()는 두 번째 매개변수를 배열 형태로 넣게된다는 차이점이 있다.(유사 배열)
  • bind
    • 문법: func.bind(thisArg[, arg1[, arg2[, …]]])
      • thisArg: 바인딩 함수가 타겟 함수의 this에 전달하는 값
      • arg1, arg2, …: func에 호출되어야 하는 인수
    • bind()는 새롭게 바인딩한 함수를 만든다. 바인딩한 함수는 원본 함수 객체를 감싸는 함수이다. 쉽게 말해 bind()는 call(), apply()와 같이 함수가 가리키고 있는 this를 바꾸지만 호출되지는 않는다. 즉, call(this, 1, 2, 3)은 bind(this)(1, 2, 3)과 같다는 말이다.
var member1 = {
  id: "jenny",
  favorite: function(friend, food) {
    console.log(friend + "" + this.id + "" + food + "를 좋아합니다.");
  }
};

var member2 = {
  id: "jisu"
};

member1.favorite("lose", "sandwitch"); // lose와 jenny는 sandwitch를 좋아합니다.
member1.favorite.call(member2, "lose", "sandwitch"); // lose와 jisu는 sandwitch를 좋아합니다.
member1.favorite.apply(member2, ["lose", "sandwitch"]); // lose와 jisu는 sandwitch를 좋아합니다.
member1.favorite.bind(member2)("lose", "sandwitch"); // lose와 jisu는 sandwitch를 좋아합니다.