Что такое this и как оно работает в стрелочной функции?
this в JavaScript — это ключевое слово, которое указывает на контекст выполнения функции. Значение this зависит от того, как вызывается функция, а не от того, где она объявлена.
1. Поведение this в обычных функциях
В обычной функции (function) значение this определяется в момент вызова:
-
В глобальном контексте (в браузере) this ссылается на window.
-
В методах объекта — на сам объект.
-
В функциях-обработчиках событий — на элемент, на котором висит обработчик.
-
В конструкторах (new) — на создаваемый экземпляр.
-
В строгом режиме ('use strict') в глобальной функции this будет undefined.
Примеры:
function show() {
console.log(this);
}
show(); // в браузере: window (в обычном режиме)
const obj = {
name: 'Alice',
greet() {
console.log(this.name);
}
};
obj.greet(); // Alice
const person = {
name: 'Bob',
sayHi: function () {
setTimeout(function () {
console.log(this.name); // undefined или window.name
}, 1000);
}
};
person.sayHi();
2. Особенности this в стрелочной функции
Стрелочные функции (=>) не имеют своего собственного this. Вместо этого они наследуют this из окружающего лексического контекста, в котором были созданы.
Это значит:
-
this в стрелочной функции не зависит от способа вызова;
-
this не меняется при использовании методов .call(), .apply(), .bind();
-
стрелочные функции нельзя использовать как конструкторы (будет ошибка).
Пример:
const obj = {
name: 'Alice',
greet: function () {
const arrow = () => {
console.log(this.name);
};
arrow();
}
};
obj.greet(); // Alice
В этом примере arrow — стрелочная функция. Она определена внутри метода greet, а this в arrow берётся из greet, то есть this указывает на obj.
3. Отличие от обычной функции внутри метода
const obj = {
name: 'Bob',
greet: function () {
setTimeout(function () {
console.log(this.name);
}, 1000);
}
};
obj.greet(); // undefined
Здесь внутри setTimeout обычная функция. this в ней — это глобальный объект (или undefined в strict mode).
Решение с помощью стрелочной функции:
const obj = {
name: 'Bob',
greet: function () {
setTimeout(() => {
console.log(this.name);
}, 1000);
}
};
obj.greet(); // Bob
4. Стрелочные функции и методы объектов
Если стрелочную функцию назначить как метод объекта, this не будет указывать на сам объект:
const obj = {
name: 'John',
greet: () => {
console.log(this.name);
}
};
obj.greet(); // undefined
this в стрелочной функции здесь ссылается не на obj, а на внешний контекст (например, window), потому что стрелка не создаёт свой this.
5. Влияние call/apply/bind на стрелочные функции
Стрелочную функцию нельзя привязать к другому this:
const arrow = () => {
console.log(this);
};
const obj = { a: 1 };
arrow.call(obj); // всё равно — внешний \`this\`
arrow.apply(obj); // то же самое
arrow.bind(obj)(); // не сработает
6. Внутри классов
В классах стрелочные функции полезны для сохранения контекста this, особенно в колбэках:
class Counter {
constructor() {
this.count = 0;
}
start() {
setInterval(() => {
this.count++;
console.log(this.count);
}, 1000);
}
}
const c = new Counter();
c.start();
Стрелочная функция внутри setInterval берёт this из метода start, то есть указывает на экземпляр класса.
7. Использование в обработчиках событий
Если обработчик определён через стрелочную функцию, this внутри будет не элемент, а внешний контекст:
const button = document.querySelector('button');
button.addEventListener('click', () => {
console.log(this); // НЕ <button>, а внешний \`this\`
});
Если нужно, чтобы this указывал на элемент — использовать обычную функцию:
button.addEventListener('click', function () {
console.log(this); // <button>
});
8. Стрелочные функции и конструкция new
Стрелочную функцию нельзя использовать как конструктор:
const A = () => {};
const obj = new A(); // TypeError: A is not a constructor
Потому что у стрелочной функции отсутствует свойство [[Construct]] и this.
9. Поведение в стрелке внутри стрелки
const outer = () => {
return () => {
console.log(this);
};
};
const fn = outer();
fn(); // \`this\` берется из внешней стрелки — она тоже не имеет \`this\`
Обе стрелки не создают this. В результате this будет из контекста, где была объявлена outer.
10. Поведение в строгом режиме
Стрелочные функции всегда работают так, как будто находятся в строгом режиме. Но this в них не определяется — берётся из внешнего лексического окружения:
'use strict';
const obj = {
val: 1,
arrow: () => {
console.log(this); // window или undefined в node
}
};
obj.arrow(); // window в браузере
11. В замыканиях
Стрелочная функция часто используется вместе с замыканиями для сохранения контекста:
function Timer() {
this.seconds = 0;
setInterval(() => {
this.seconds++;
console.log(this.seconds);
}, 1000);
}
new Timer();
Без стрелки this внутри setInterval не указывал бы на экземпляр Timer.
12. Поведение в классе и bind
Стрелка — альтернатива bind в методах классов:
class User {
constructor(name) {
this.name = name;
}
sayHi = () => {
console.log(this.name);
};
}
const user = new User('Elena');
const f = user.sayHi;
f(); // Elena
Если бы sayHi был обычным методом, при передаче f = user.sayHi this бы терялся. Стрелка сохраняет this автоматически.