В TypeScript для методов внутри класса тип this по умолчанию — это текущий экземпляр класса. Однако, если определять методы через стрелочные функции, контекст this будет привязан к моменту объявления, а не вызова.
Обычный метод:
class Counter { value = 0; increment() { this.value++; } }
Стрелочная функция:
class Counter { value = 0; increment = () => { this.value++; } }
Тонкости:
this при передаче их как колбэков (например, в event listener'ы).this в сигнатуре метода для дополнительной проверки:class Foo { bar(this: Foo) { // ... } }
Чем отличается
increment()иincrement = () => {}в классе? Как это сказывается на контексте this при использовании в качестве колбэка?
Неправильный ответ:
Правильный ответ:
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 = ...), что создавало новые копии функций для каждого экземпляра, а не одно определение на прототипе, как с обычным методом. В результате увеличилось потребление памяти, и понадобилась оптимизация.