TS에서 this 바인딩

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);

© 2021. All rights reserved.

Powered by Hydejack v7.5.2