Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI21 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Что такое this?
this — это один из самых запутанных концептов в JavaScript. Он представляет контекст выполнения функции и его значение зависит от того, как функция была вызвана.
Краткое определение
this это объект, который "принадлежит" коду при его выполнении. Его значение определяется в момент вызова функции, а не в момент её определения.
const user = {
name: 'John',
greet() {
console.log(`Hello, ${this.name}`); // this = user
}
};
user.greet(); // Hello, John
Правила определения this
1. Метод объекта (Method invocation)
Когда функция вызывается как метод объекта, this указывает на этот объект:
const person = {
name: 'Alice',
age: 30,
sayName() {
console.log(this.name); // this = person
},
birthday() {
this.age++; // Изменяем свойство person
}
};
person.sayName(); // Alice
person.birthday(); // Увеличиваем age
2. Простой вызов функции (Function call)
При простом вызове функции this указывает на глобальный объект (window в браузере, global в Node.js) или undefined в strict mode:
function sayHello() {
console.log(this); // undefined в strict mode, window в обычном
}
sayHello();
// В браузере (обычный режим)
console.log(this); // Window { window: Window, ... }
// В strict mode
'use strict';
function test() {
console.log(this); // undefined
}
test();
3. Конструктор (new)
При вызове функции с new, this указывает на новый объект:
function Person(name) {
this.name = name; // this = новый объект
this.greet = function() {
console.log(`Hi, I'm ${this.name}`);
};
}
const john = new Person('John');
john.greet(); // Hi, I'm John
console.log(john.name); // John
4. Явное указание контекста (call, apply, bind)
Mожно явно указать значение this используя методы call, apply или bind:
const greeting = function() {
console.log(`Hello, ${this.name}`);
};
const alice = { name: 'Alice' };
const bob = { name: 'Bob' };
// call — передаём this как первый аргумент
greeting.call(alice); // Hello, Alice
greeting.call(bob); // Hello, Bob
// apply — подобно call, но принимает массив аргументов
const greetWithAge = function(age) {
console.log(`Hello, ${this.name}, age ${age}`);
};
greetWithAge.apply(alice, [25]); // Hello, Alice, age 25
// bind — создаёт новую функцию с привязанным контекстом
const boundGreeting = greeting.bind(alice);
boundGreeting(); // Hello, Alice (вне зависимости от контекста вызова)
Примеры проблем с this
Проблема 1: потеря контекста
const person = {
name: 'John',
greet() {
console.log(this.name);
}
};
// Когда передаём метод как callback, теряем контекст
const greetFunc = person.greet;
greetFunc(); // undefined (или ошибка в strict mode)
// Решение 1: использовать стрелочную функцию
const person2 = {
name: 'John',
greet: () => {
console.log(this.name); // ❌ стрелочная функция наследует this снаружи
},
greetProper() {
// ✅ Правильно для методов
console.log(this.name);
}
};
// Решение 2: использовать bind
const greetBound = person.greet.bind(person);
greetBound(); // John
// Решение 3: использовать стрелочную функцию как property
const person3 = {
name: 'John',
greet: () => {
// ❌ Неправильно — стрелочная функция не имеет своего this
}
};
Проблема 2: this в Event Listeners
const button = document.querySelector('button');
const handler = {
clicks: 0,
handleClick() {
// ❌ ПРОБЛЕМА: this = button, а не handler
this.clicks++; // Добавляет свойство на button, а не handler
}
};
button.addEventListener('click', handler.handleClick); // Потеря контекста
// Решение 1: bind
button.addEventListener('click', handler.handleClick.bind(handler));
// Решение 2: стрелочная функция
button.addEventListener('click', () => handler.handleClick());
// Решение 3: стрелочная функция как property
const handler2 = {
clicks: 0,
handleClick: () => {
// ❌ Стрелочная функция наследует this из внешней области
this.clicks++;
}
};
Проблема 3: this в setTimeout
const person = {
name: 'John',
showNameLater() {
// ❌ this = undefined (в strict mode) или window
setTimeout(function() {
console.log(this.name); // undefined
}, 1000);
},
// ✅ Решение: стрелочная функция
showNameLaterFixed() {
setTimeout(() => {
console.log(this.name); // this наследуется из showNameLaterFixed
}, 1000);
},
// Альтернатива: bind
showNameLaterBind() {
setTimeout(function() {
console.log(this.name);
}.bind(this), 1000);
}
};
person.showNameLaterFixed(); // John (после 1 секунды)
this в классах
class Person {
constructor(name) {
this.name = name;
}
// Метод: this = экземпляр класса
greet() {
console.log(`Hello, ${this.name}`);
}
// Стрелочная функция как property: this = экземпляр класса
greetArrow = () => {
console.log(`Hello, ${this.name}`);
}
}
const john = new Person('John');
john.greet(); // Hello, John
john.greetArrow(); // Hello, John
// Проблема с методами
const greetFunc = john.greet;
greetFunc(); // ❌ undefined
// Стрелочные функции как properties решают проблему
const greetArrowFunc = john.greetArrow;
greetArrowFunc(); // ✅ Hello, John
this vs стрелочные функции
const obj = {
name: 'Object',
// ✅ Обычная функция: this = obj
regularMethod() {
console.log(this.name); // 'Object'
},
// ❌ Стрелочная функция: this = внешний контекст
arrowMethod: () => {
console.log(this.name); // undefined
},
// ✅ Правильно для callback'ов
handleCallback: function() {
setTimeout(() => {
// Стрелочная функция наследует this из handleCallback
console.log(this.name); // 'Object'
}, 100);
}
};
obj.regularMethod(); // Object
obj.arrowMethod(); // undefined
obj.handleCallback(); // Object (после 100ms)
Таблица: когда какой this
| Контекст | this указывает на |
|---|---|
| Метод объекта | Объект |
| Простой вызов | undefined (strict) или window |
| new Constructor | Новый объект |
| .call(obj) | obj |
| .apply(obj) | obj |
| .bind(obj) | obj |
| Стрелочная функция | Внешний this (лексический) |
| Event listener | Элемент (addEventListener) |
Практические примеры в React
class Counter extends React.Component {
constructor(props) {
super(props);
this.count = 0;
}
// ❌ Проблема: this может быть undefined
increment() {
this.count++; // this может быть undefined
}
// Решение 1: bind в конструкторе
incrementBound() {
this.count++;
}
// Решение 2: стрелочная функция как property
incrementArrow = () => {
this.count++;
}
render() {
return (
<div>
<button onClick={this.incrementArrow}>Increment</button>
</div>
);
}
}
// В функциональных компонентах этой проблемы нет
function CounterFunc() {
const [count, setCount] = React.useState(0);
const increment = () => {
setCount(count + 1);
};
return <button onClick={increment}>Increment</button>;
}
Ключевые выводы
- this определяется при вызове функции, а не при её определении
- В методах объекта
thisуказывает на объект - При простом вызове
thisнеопределён (strict mode) или window - С new
thisуказывает на новый объект - call, apply, bind позволяют явно указать контекст
- Стрелочные функции наследуют
thisиз внешней области - В современном коде часто используются стрелочные функции чтобы избежать проблем с
this