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.