TS에서 this 바인딩
this
TS, JS에서 this
는 함수가 호출되는 방식에 따라 동적으로 결정된다.
좀더 자세히 알아보고 싶어서 TS로 직접 코드를 짜며 실험해봤다.
이 글은 2023년 8월 11일 Node 20.5.0 버전, TS 5.1.6 버전 기준으로 작성된 글이다.
개발 환경에 따라 결과가 달라질 수 있으니 참고만 하길 바란다.
function
키워드로 선언된 함수
함수 선언문, 함수 표현식에는 function
키워드를 사용한다.
function
키워드로 선언된 함수는 this
를 언제든지 새로 바인딩할 수 있다.
call
, apply
, bind
메서드를 사용하여 this
를 새로 바인딩할 수 있다.
interface This {
explain: string;
}
function func(this: This) {
console.log(this.explain);
}
func.call({ explain: 'this is func' }); // this is func
const boundFunc = func.bind({ explain: 'this is boundFunc' });
boundFunc(); // this is boundFunc
화살표 함수
화살표 함수는 정의된 시점의 상위 스코프의 this
를 그대로 물려받는다.
따라서 화살표 함수는 call
, apply
, bind
메서드를 사용하여 this
를 새로 바인딩할 수 없다.
const arrowFunc = () => {
// 사실 애초에 TS 컴파일러가 이 부분에서 이미 에러를 발생시킨다.
// 전역 객체를 참조하는 것 자체를 허용하지 않기 때문이다.
// 또 전역 객체의 타입 `globalThis` 에 `explain` 프로퍼티가 없기도 하다.
// @ts-ignore 를 사용하여 컴파일러가 에러를 발생시키지 않도록 했다고 가정하자.
console.log(this.explain);
};
arrowFunc.call({ explain: 'this is arrowFunc' }); // undefined
// `arrowFunc` 의 `this` 는 상위 스코프의 `this`, 현 시점에서 전역 객체를 가리킨다.
// 전역 객체의 `explain` 프로퍼티는 존재하지 않으므로 undefined 가 출력된다.
단, 상위 스코프의 this
가 바뀐다면 이를 참조하는 화살표 함수의 this
도 바뀐다.
function boundSomeFunc(this: This) {
return () => {
console.log(this.explain);
};
}
boundSomeFunc.call({ explain: "`this` defined at call time" })(); // `this` defined at call time
혹은 this
가 바인드된 함수 안에서 this
가 변화하는 경우에도 마찬가지다.
function thisChangedAfter1Sec(this: This) {
this.explain = "`this` is not changed";
setTimeout(() => {
this.explain = "`this` is changed after 1 sec";
}, 1000);
return () => {
console.log(this.explain);
};
}
const arrowFromThisChangedAfter1Sec = thisChangedAfter1Sec.call({});
arrowFromThisChangedAfter1Sec(); // `this` is not changed
setTimeout(() => {
arrowFromThisChangedAfter1Sec(); // `this` is changed after 1 sec
}, 2000);