"Arrow 함수와 declared 함수는 스타일 variant 아냐. `this` 에 대해 다른 결정 하고, 그 결정은 영구적."
결정적 차이
`function` 선언의 `this` 는 dynamic. `this` 의 값은 함수 호출 방식으로 결정: method 로 (obj.fn() → `this` 가 `obj`), plain 함수로 (fn() → strict mode 에서 `this` 가 undefined), fn.call(other) 통해 (→ `this` 가 `other`), new fn() 통해 (→ `this` 가 새 instance).
Arrow 함수의 `this` 는 lexical. 정의 시점에 둘러싼 scope 에서 `this` 캡처. 한 번 캡처되면 절대 안 바뀜 — arrow 함수에 .call(other) 호출해도 `this` 에 아무것도 안 함.
그게 전체 규칙. 다른 모든 arrow-vs-declared 토론이 그것의 downstream.
각각 손 뻗을 때
Arrow 함수: callback, class method 안 event handler, inline helper, `this` 가 쓴 줄에서 의미한 거 의미하길 원하는 어디든. Modern TypeScript 의 90%+ case.
함수 선언 / 표현식: `this` 가 object 여야 하는 object method, class method (이미 자동으로 this-binding 의미 얻음), constructor, generator 함수. 그리고 진짜로 `this` 가 rebindable 하길 원하는 드문 case.
Class-method gotcha
Class 가 둘 다 섞어. Class method 는 내부적으로 함수 선언이라, `this` 가 dynamic. 즉 obj.method 를 callback 으로 전달하면 `this` 잃어:
class Counter {
count = 0;
increment() { this.count++ }
}
const c = new Counter();
setTimeout(c.increment, 1000); // ❌ 호출 시 `this` undefined
setTimeout(() => c.increment(), 1000); // ✅ arrow 가 `c` 보존
두 흔한 해결: 호출을 arrow 로 감싸기 (위), 또는 method 를 arrow-함수 field 로 정의 (increment = () => { this.count++ } — 생성 시점에 `this` 캡처). 두 번째는 비용 있어 — prototype 의 하나 대신 instance 마다 새 함수 — 근데 binding 이슈 제거.