October 15, 2021

setTimeout에 메서드를 전달할 때처럼, 객체 메서드를 콜백으로 전달할 때 ’this 정보가 사라지는’ 문제가 생깁니다.

이번 챕터에선 이 문제를 어떻게 해결할지에 대해 알아보겠습니다.

사라진 ‘this’

앞서 다양한 예제를 통해 this 정보가 사라지는 문제를 경험해보았습니다. 객체 메서드가 객체 내부가 아닌 다른 곳에 전달되어 호출되면 this가 사라집니다.

아래 funcUser에는 this가 user로 고정된 func이 할당됩니다.

let user = {
  firstName: "John"
};

function func() {
  alert(this.firstName);
}

*let funcUser = func.bind(user);
funcUser(); // John*

여기서 func.bind(user)는 func의 this를 user로 '바인딩한 변형’이라고 생각하시면 됩니다.

인수는 원본 함수 func에 ‘그대로’ 전달됩니다.

let user = {
  firstName: "John",
  sayHi() {
    alert(`Hello, ${this.firstName}!`);
  }
};

*let sayHi = user.sayHi.bind(user); // (*)*// 이제 객체 없이도 객체 메서드를 호출할 수 있습니다.
sayHi(); // Hello, John!

setTimeout(sayHi, 1000); // Hello, John!

// 1초 이내에 user 값이 변화해도
// sayHi는 기존 값을 사용합니다.
user = {
  sayHi() { alert("또 다른 사용자!"); }
};

(*)로 표시한 줄에서 메서드 user.sayHi를 가져오고, 메서드에 user를 바인딩합니다. sayHi는 이제 ‘묶인(bound)’ 함수가 되어 단독으로 호출할 수 있고 setTimeout에 전달하여 호출할 수도 있습니다. 어떤 방식이든 컨택스트는 원하는 대로 고정됩니다.

아래 예시를 실행하면 인수는 ‘그대로’ 전달되고 bind에 의해 this만 고정된 것을 확인할 수 있습니다.

let user = {
  firstName: "John",
  say(phrase) {
    alert(`${phrase}, ${this.firstName}!`);
  }
};

let say = user.say.bind(user);

say("Hello"); // Hello, John (인수 "Hello"가 say로 전달되었습니다.)
say("Bye"); // Bye, John ("Bye"가 say로 전달되었습니다.)

Untitled