Ответ
Контекст (this) в JavaScript — это специальная переменная, которая указывает на объект, в контексте которого выполняется функция. Значение this определяется способом вызова функции, а не местом её объявления.
Основные правила определения this:
-
Глобальный контекст (Node.js):
console.log(this); // {} в модулях, global в обычном скрипте // В строгом режиме модулей Node.js this === exports -
Метод объекта:
const user = { name: 'Alice', greet() { console.log(`Hello, ${this.name}`); } };
user.greet(); // Hello, Alice (this = user)
// Потеря контекста const greetFunc = user.greet; greetFunc(); // Hello, undefined (this = global или undefined в strict mode)
3. **Конструктор (с `new`):**
```javascript
function User(name) {
this.name = name;
this.isAdmin = false;
}
const admin = new User('Bob');
console.log(admin.name); // Bob (this = новый объект)
- Явное указание контекста:
function showInfo(role, department) { console.log(`${this.name} - ${role} (${department})`); }
const employee = { name: 'Charlie' };
// call - вызывает сразу с переданными аргументами showInfo.call(employee, 'Developer', 'Engineering');
// apply - аналогично call, но аргументы передаются массивом showInfo.apply(employee, ['Developer', 'Engineering']);
// bind - создает новую функцию с привязанным контекстом const boundShowInfo = showInfo.bind(employee, 'Developer'); boundShowInfo('Engineering');
5. **Стрелочные функции:**
```javascript
const obj = {
value: 42,
regularFunc: function() {
console.log(this.value); // 42 (this = obj)
const innerArrow = () => {
console.log(this.value); // 42 (this унаследован от regularFunc)
};
innerArrow();
},
arrowFunc: () => {
console.log(this.value); // undefined (this унаследован от внешней области)
}
};
obj.regularFunc();
obj.arrowFunc();
Особенности в Node.js:
// В обработчиках событий и колбэках часто теряется контекст
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {
constructor() {
super();
this.value = 'test';
// Проблема: потеря контекста
this.on('event', this.handleEvent); // this будет undefined
// Решение 1: стрелочная функция
this.on('event', () => this.handleEvent());
// Решение 2: bind
this.on('event', this.handleEvent.bind(this));
}
handleEvent() {
console.log(this.value);
}
}
// В асинхронных операциях
const fs = require('fs').promises;
class FileProcessor {
constructor(filename) {
this.filename = filename;
}
async process() {
// Стрелочная функция сохраняет контекст
const content = await fs.readFile(this.filename, 'utf8');
return this.transform(content);
}
transform(content) {
return content.toUpperCase();
}
}
Практическое правило: Используйте стрелочные функции для сохранения контекста в колбэках и обработчиках, а bind() или call()/apply() когда нужно явно указать контекст.
Ответ 18+ 🔞
Слушай, я тут подумал — объяснить про this в JavaScript надо так, чтобы даже мартышка с бананом поняла. Это ж, бля, одна из тех тем, от которой у новичков волосы дыбом встают, а потом они охуевают, когда осознают, насколько всё просто на самом деле.
Представь себе: this — это как указатель на того, кто сейчас водит за ручку выполнение кода. Не там, где функцию написали, а там, где её вызвали. Вот и весь секрет, ёпта.
Смотри, основные сценарии:
-
В глобальной области (Node.js) — тут уже интересно начинается:
console.log(this); // {} в модулях, global в обычном скрипте // В строгом режиме модулей Node.js this === exportsТо есть если ты просто в файле на Node пишешь —
thisможет быть пустым объектом или глобальным контекстом. Зависит от того, модуль это или скрипт. Но, честно, да похуй на эту разницу, пока ты не лезешь в системное программирование. -
Метод объекта — вот тут уже веселее:
const user = { name: 'Alice', greet() { console.log(`Hello, ${this.name}`); } };
user.greet(); // Hello, Alice (this = user) — всё логично
// А вот сейчас будет магия потери контекста, готовься const greetFunc = user.greet; greetFunc(); // Hello, undefined (this = global или undefined в strict mode)
Видишь? Функцию отцепили от объекта и вызвали просто так — и `this` уплыл в неизвестность. **Овердохуища** людей на этом ловятся!
3. **Конструктор (с `new`)** — тут `this` создаётся заново:
```javascript
function User(name) {
this.name = name;
this.isAdmin = false;
}
const admin = new User('Bob');
console.log(admin.name); // Bob (this = новый объект)
new говорит: «Слушай, дружок, я сейчас создам новый объект, и this внутри функции будет указывать на него». Красота.
- Явное указание контекста — когда ты сам решаешь, кто будет
this:function showInfo(role, department) { console.log(`${this.name} - ${role} (${department})`); }
const employee = { name: 'Charlie' };
// call — вызываем сразу, передаём аргументы через запятую showInfo.call(employee, 'Developer', 'Engineering');
// apply — то же самое, но аргументы массивом showInfo.apply(employee, ['Developer', 'Engineering']);
// bind — создаёт новую функцию с привязанным намертво контекстом const boundShowInfo = showInfo.bind(employee, 'Developer'); boundShowInfo('Engineering');
Вот это уже мощь, **ебушки-воробушки**! Сам управляешь, как кукловод.
5. **Стрелочные функции** — а вот это вообще отдельная история, **ни хуя себе** удобная:
```javascript
const obj = {
value: 42,
regularFunc: function() {
console.log(this.value); // 42 (this = obj)
const innerArrow = () => {
console.log(this.value); // 42 (this унаследован от regularFunc)
};
innerArrow();
},
arrowFunc: () => {
console.log(this.value); // undefined (this унаследован от внешней области)
}
};
obj.regularFunc();
obj.arrowFunc();
Запомни раз и навсегда: стрелочная функция не имеет своего this. Она берёт его из внешнего лексического окружения. Поэтому в методах объекта через стрелочную функцию — доверия ебать ноль, this будет не объект, а что-то снаружи.
Особенности в Node.js, которые всех бесят:
// В обработчиках событий и колбэках контекст часто теряется
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {
constructor() {
super();
this.value = 'test';
// Проблема: потеря контекста — классика!
this.on('event', this.handleEvent); // this будет undefined
// Решение 1: стрелочная функция (проще всего)
this.on('event', () => this.handleEvent());
// Решение 2: bind (более канонично)
this.on('event', this.handleEvent.bind(this));
}
handleEvent() {
console.log(this.value);
}
}
// В асинхронных операциях тоже следи
const fs = require('fs').promises;
class FileProcessor {
constructor(filename) {
this.filename = filename;
}
async process() {
// Стрелочная функция — наш спаситель
const content = await fs.readFile(this.filename, 'utf8');
return this.transform(content);
}
transform(content) {
return content.toUpperCase();
}
}
Итоговое практическое правило, чтобы не ебал себе мозг:
- Используй стрелочные функции для колбэков и обработчиков — они контекст не теряют.
- Используй
bind(),call()илиapply(), когда нужно явно и жёстко указать, кто будетthis. - И главное — подозрение ебать чувствуй, когда видишь обычную функцию в колбэке. Скорее всего, контекст уплывёт, и будет тебе хитрая жопа с
undefined.
Вот и вся магия. Не так страшен чёрт, как его малюют.