this в JavaScript: простое руководство с примерами, ошибками и лучшими практиками
Запрос «this в JavaScript» остаётся одним из самых популярных среди начинающих и продолжающих разработчиков. Этот ключевой концепт влияет на поведение методов, классов, обработчиков событий и коллбэков. Разберёмся детально и практично, с примерами и анти-примерами.
Что такое this в JavaScript
Ключевое слово this — это ссылка на текущий контекст выполнения. Важно: в JavaScript значение this определяется способом вызова функции, а не местом её объявления (кроме стрелочных функций, о них ниже).
function show() {
console.log(this);
}
show(); // Значение зависит от режима: window (нестрогий) или undefined (strict)
Глобальный контекст и строгий режим
- В браузере без strict-режима: this === window.
- В strict-режиме: this === undefined.
- В модулях ES (type="module"): на верхнем уровне this === undefined.
'use strict';
function foo() {
console.log(this); // undefined
}
foo();
Вызов как метод объекта
Когда функция вызвана как метод объекта, this указывает на этот объект.
const user = {
name: 'Алиса',
say() {
console.log('Привет, ' + this.name);
}
};
user.say(); // Привет, Алиса
const speak = user.say;
speak(); // В strict: ошибка/undefined, без strict: window — this потерян
Вывод: при передаче метода как коллбэка this теряется. Решения — bind, стрелочная обёртка или явный вызов через call/apply.
Конструкторы и классы: new
При вызове функции с new создаётся новый объект, и this ссылается на него.
function Person(name) {
this.name = name;
}
const p = new Person('Боб');
console.log(p.name); // Боб
class Counter {
constructor() {
this.value = 0;
}
inc() { this.value++; }
}
const c = new Counter();
c.inc();
console.log(c.value); // 1
call, apply и bind: ручное управление this
Методы call и apply вызывают функцию немедленно с заданным this. Разница — в передаче аргументов.
function greet(greeting, punctuation) {
console.log(greeting + ', ' + this.name + punctuation);
}
const ctx = { name: 'Кира' };
greet.call(ctx, 'Привет', '!'); // Привет, Кира!
greet.apply(ctx, ['Здравствуйте', '!!']); // Здравствуйте, Кира!!
bind возвращает новую функцию с «прикреплённым» this (и, опционально, частично применёнными аргументами).
const user = { name: 'Лев' };
function sayHi() { console.log('Hi, ' + this.name); }
const sayHiFromUser = sayHi.bind(user);
sayHiFromUser(); // Hi, Лев
Стрелочные функции и this
Стрелочные функции не имеют собственного this. Они захватывают this из внешнего (лексического) окружения.
const counter = {
value: 0,
incLater() {
setTimeout(() => {
this.value++;
console.log(this.value);
}, 100);
}
};
counter.incLater(); // 1 — стрелка взяла this из incLater()
Анти-пример: стрелка как метод объекта — часто ошибка.
const obj = {
name: 'X',
say: () => console.log(this.name)
};
obj.say(); // this не obj; в модуле: undefined, в браузере вне strict: window
Обработчики событий в DOM
В addEventListener при обычной функции this указывает на элемент, на котором висит обработчик. В стрелке — на внешний контекст. Надёжнее использовать event.currentTarget.
document.querySelector('#btn').addEventListener('click', function(e) {
console.log(this === e.currentTarget); // true
});
document.querySelector('#btn2').addEventListener('click', (e) => {
console.log(this); // лексический this, не элемент
console.log(e.currentTarget); // правильный способ доступа к элементу
});
setTimeout/setInterval: потеря контекста
Если передать метод напрямую в таймер, this, скорее всего, потеряется.
const timerDemo = {
v: 0,
inc() { this.v++; },
run() {
setTimeout(this.inc, 50); // потеряем this
setTimeout(() => this.inc(), 100); // ок
setTimeout(this.inc.bind(this), 150); // ок
}
};
timerDemo.run();
this в массивах и переборах
У многих методов массивов есть необязательный второй аргумент thisArg.
const tools = {
prefix: '#',
addPrefix(x) { return this.prefix + x; }
};
const res = ['a','b'].map(tools.addPrefix, tools);
console.log(res); // ['#a','#b']
Без передачи thisArg будет ошибка/undefined внутри addPrefix.
Частые ошибки и как их избегать
- Деструктуризация методов: const { push } = Array.prototype; push(…)
- Передача методов как коллбэков без bind.
- Использование стрелок как методов объекта (теряется ожидаемое this).
- Ожидание window в модулях: на верхнем уровне this === undefined.
// Исправление деструктуризации
const push = Array.prototype.push.call.bind(Array.prototype.push);
const arr = [1];
push(arr, 2);
console.log(arr); // [1,2]
Памятка по this в JavaScript
- Обычный вызов функции: this — undefined (strict) или window (без strict).
- Метод объекта: this — сам объект.
- Конструктор/new: this — новый экземпляр.
- call/apply/bind: this задаётся явно.
- Стрелка: this берётся снаружи, своего нет.
- DOM-обработчики: this — элемент (для обычной функции), используйте event.currentTarget.
Мини-практика: безопасный счётчик
class SafeCounter {
value = 0;
// полевой синтаксис со стрелкой фиксирует this без bind в конструкторе
inc = () => { this.value++; };
log = () => console.log(this.value);
}
const sc = new SafeCounter();
const { inc, log } = sc;
inc(); inc();
log(); // 2
В классах вы можете выбирать между методами прототипа и стрелочными полями. Второй вариант часто проще для коллбэков, так как не требует manual bind.
Советы из практики
- Для коллбэков и таймеров используйте стрелочные функции или заранее привязывайте методы через bind.
- В React/Vue/современных фреймворках предпочитайте стрелки для обработчиков или class fields, чтобы не терять this.
- В модулях не полагайтесь на глобальный this — используйте явные ссылки (window, globalThis).
- В обработчиках событий чаще используйте event.currentTarget вместо this для читаемости и надёжности.
Куда двигаться дальше
Если хотите системно закрыть пробелы в основах и уверенно писать современный код, рекомендую пройти практический курс: Прокачать JavaScript и отработать this на практике. Много задач, разбор типичных ошибок и пошаговый рост от базовых тем к продвинутым.
Итоги
this в JavaScript — динамическая, но логичная концепция. Поймите, как функция вызвана, и вы почти всегда предскажете значение this. Используйте стрелочные функции для коллбэков, bind для методов, а в DOM опирайтесь на event.currentTarget. Эти простые правила избавят от большей части ошибок и сделают код предсказуемым.
-
Создано 27.10.2025 17:01:06
-
Михаил Русаков

Комментарии (0):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.