타입스크립트에서 클래스 내부의 메서드에 대한 this 타입은 기본적으로 현재 클래스 인스턴스를 나타냅니다. 그러나 메서드를 화살표 함수로 정의하면 this의 컨텍스트는 호출 시점이 아닌 선언 시점에 바인딩됩니다.
일반 메서드:
class Counter { value = 0; increment() { this.value++; } }
화살표 함수:
class Counter { value = 0; increment = () => { this.value++; } }
주요 사항:
this의 컨텍스트를 잃습니다(예: 이벤트 리스너에서).class Foo { bar(this: Foo) { // ... } }
increment()와increment = () => {}의 차이는 무엇인가요? 콜백으로 사용할 때 this의 컨텍스트에 어떤 영향을 미치나요?
틀린 답변:
올바른 답변:
setTimeout(counter.increment, 0), 이 경우 this는 undefined(엄격 모드) 또는 window(비엄격 모드)가 됩니다. 반면 화살표 함수는 자신의 환경을 유지합니다:class Demo { value = 1; inc() { console.log(this.value); } incArrow = () => { console.log(this.value); } } const d = new Demo(); setTimeout(d.inc, 0); // undefined 또는 오류 setTimeout(d.incArrow, 0); // 1
이야기
반응형 프레임워크 프로젝트에서 클래스 메서드가 명시적 bind 없이 콜백으로 직접 전달되었습니다. 이로 인해 this가 undefined가 되어 this 속성 접근 시 오류가 발생하여 애플리케이션이 중단되었습니다. 이 문제는 메서드를 화살표 함수로 다시 작성하거나 명시적으로 bind하여 해결했습니다.
이야기
개발자가 메서드에서 this의 타입을 명시했지만, 해당 메서드 내 화살표 함수의 타입화는 잊어버렸습니다. 결과적으로 중첩된 콜백 내부의 this는 클래스 인스턴스가 아닌 window를 가리켰습니다. 팀은 상태 유출 문제에 직면하여 이벤트 아키텍처를 변경해야 했습니다.
이야기
큰 UI 컴포넌트가 애플리케이션을 느리게 만든 이유는 모든 메서드가 클래스의 화살표 필드로 정의되어 있었기 때문입니다(new Counter().increment = ...). 이로 인해 각 인스턴스에 대해 새로운 함수 복사본이 생성되어 일반 메서드와 같이 프로토타입에 대한 하나의 정의가 아니었습니다. 이로 인해 메모리 소비가 증가하고 최적화가 필요했습니다.