Перейти к содержимому

this — 4 правила + arrow

В одной фразе: this — динамически определяемый контекст, зависящий от того как вызвана функция, а не где она определена (исключение — стрелочные функции с лексическим this). На собесе проверяют все 4 правила, их приоритет и поведение при “потере” this.

4 rules (priority high->low):
1. new fn()       -> this = new {}
2. fn.call/apply/bind(x) -> this = x
3. obj.fn()       -> this = obj
4. fn()           -> this = undefined (strict) / globalThis
arrow fn: this = lexical (from definition scope)
// Правило 3 (implicit) vs потеря this при извлечении метода
const user = {
name: 'Alice',
greet() { return `Hello, ${this.name}`; }
};
user.greet(); // 'Hello, Alice' — this = user (правило 3)
const greetFn = user.greet; // извлекаем — теряем контекст
greetFn(); // 'Hello, undefined' / TypeError (strict)
// this больше не user — применяется правило 4 (default binding)
// Правило 1 (new) и стрелка в методе (lexical this)
function Person(name) {
this.name = name; // new: this = только что созданный объект
}
const p = new Person('Bob'); // p.name = 'Bob'
// Стрелка захватывает this из места определения
const timer = {
ticks: 0,
start() {
// Arrow: this = timer (из start()), не меняется при вызове через setInterval
setInterval(() => this.ticks++, 1000);
}
};
timer.start(); // работает корректно
// Потеря this в callback — типичная ловушка
class EventHandler {
count = 0;
constructor() {
// ❌ this.handle — потеряет this при вызове браузером
// document.addEventListener('click', this.handle);
// ✅ 1: bind в конструкторе — создаёт новую функцию
this.handleBound = this.handle.bind(this);
// ✅ 2: arrow class field — this зафиксирован лексически
this.handleArrow = () => this.count++;
}
handle() { this.count++; } // this зависит от вызывателя
}

Итог: this определяется в runtime по месту вызова. Приоритет правил: new > explicit (call/apply/bind) > implicit (obj.fn) > default.