this
this — ссылка на контекст выполнения. Значение зависит от того, как функция вызвана, а не где объявлена.
Правила
1. Метод объекта
this = объект перед точкой:
const user = {
name: 'Алиса',
greet() {
return this.name;
},
};
user.greet(); // 'Алиса'
2. Обычная функция
this = undefined в strict mode, глобальный объект в нестрогом:
function test() {
'use strict';
console.log(this); // undefined
}
test();
3. Стрелочная функция
Своего this нет. Берётся из внешней области:
const user = {
name: 'Алиса',
greet: () => {
return this.name; // this не объект
},
};
user.greet(); // undefined
Стрелочные не подходят для методов, где нужен this объекта.
4. Конструктор
this = новый объект:
function User(name) {
this.name = name;
}
const user = new User('Алиса');
user.name; // 'Алиса'
5. call, apply, bind
Явное указание this:
function greet() {
return `Привет, ${this.name}`;
}
const user = { name: 'Алиса' };
greet.call(user); // 'Привет, Алиса'
greet.apply(user); // то же
const bound = greet.bind(user);
bound(); // то же
Потеря this
const user = {
name: 'Алиса',
greet() {
return this.name;
},
};
const fn = user.greet;
fn(); // undefined, this потерян
Решения:
// bind
const fn = user.greet.bind(user);
// стрелочная обёртка
const fn = () => user.greet();
call vs apply vs bind
- call — вызывает с аргументами через запятую
- apply — вызывает с массивом
- bind — возвращает новую функцию
fn.call(ctx, 1, 2);
fn.apply(ctx, [1, 2]);
const bound = fn.bind(ctx, 1);
Стрелочные методы в классах
class User {
name = 'Алиса';
greet = () => {
return this.name;
};
}
const user = new User();
const fn = user.greet;
fn(); // 'Алиса' — this сохранён
Стрелочное поле захватывает this из класса.
Метод в setTimeout
const user = {
name: 'Алиса',
greet() {
setTimeout(function() {
console.log(this.name); // undefined
}, 1000);
},
};
Решения:
// стрелочная
greet() {
setTimeout(() => {
console.log(this.name); // 'Алиса'
}, 1000);
}
// или bind
greet() {
setTimeout(function() {
console.log(this.name);
}.bind(this), 1000);
}
В обработчиках DOM
this в обычной функции = элемент:
button.addEventListener('click', function() {
console.log(this); // button
});
В стрелочной — из внешней области:
button.addEventListener('click', () => {
console.log(this); // не button
});
Современный код чаще использует event.currentTarget:
button.addEventListener('click', (e) => {
console.log(e.currentTarget); // button
});
Порядок приоритетов
От высшего к низшему:
new—this= новый объектbind,call,apply— явное указание- Метод объекта —
this= объект - Обычный вызов —
undefined(strict) или глобальный объект - Стрелочная —
thisиз внешней области
Итоги
thisзависит от способа вызова- Метод — объект перед точкой
- Стрелочные —
thisиз внешней области call,apply,bindдля явного указанияnewдля конструктора- Потеря
this— частая ошибка