메서드를 콜백이나, 값으로 전달하고 호출하면 this의 정보가 사라집니다.
let user = {
name : 'yuno',
sayHi() {
console.log(`${this.name}` hi);
},
}
setTimeout(user.sayHi, 1000);
setTimeout 메서드에 인수로 user.sayHi 메서드를 넘겼습니다.
setTimeout은 콜백 함수인 user.sayHi를 스케쥴러에 올리고 시간이 되면 실행합니다.
브라우저 환경에서의 setTimeout은 콜백 함수를 호출할 때, this가 window로 할당됩니다.
window.name은 undefined이 되고,
1초 뒤에 콘솔에는 'undefined hi'가 출력됩니다.
올바른 context로 실행하는 방법은 크게 두가지가 있습니다.
래퍼 함수를 활용합니다.
setTimeout(()=> {user.sayHi()}, 1000);
래퍼 함수 내에서 user.sayHi()는 외부 변수인 user 객체를 찾고,
일반적으로 메서드를 실행합니다.
다만, 콜백 실행 전에 user가 변경되면, 변경된 객체의 메서드를 실행합니다.
만약, 1초 사이에 user가 없어진다면, 위 코드는 에러를 일으킵니다.
모든 함수는 this를 수정하게 해주는 내장 메서드 bind를 지원합니다.
func.bind(context)
this를 context로 고정시킨 변형(특수 객체)을 반환합니다.
호출하면 this가 context인 func를 호출하는 것과 같은 효과를 봅니다.
let sayHi = user.sayHi.bind(user);
setTimeout(sayHi, 1000); // yuno hi
func.bind(context [,arg1][,arg2] ...)
bind 함수는 this뿐 아니라 인수도 바인딩이 가능합니다.
//multiple : 2개의 인자를 곱해주는 함수
let double = multiple.bind(null,2);
double(2) // 4
이렇게 하면 this가 null이고 첫 인수가 2인 multiple 함수의 변형을 만들 수 있습니다.
이런 방식을 부분 적용(partial application)이라 부릅니다.
부분 적용은 가독성 좋은 독립함수를 만들 수 있고,
포괄적인 함수로 덜 포괄적인 변형 함수를 만들 수 있습니다.