Потеря контекста (this) происходит, когда значение this внутри функции не ссылается на ожидаемый объект. Это может произойти, если функция вызывается в контексте, который не является объектом, или если функция передается как обычная функция, а не как метод объекта.
Существует несколько способов, которые можно использовать для избежания потери контекста:
- Использование стрелочных функций - стрелочные функции привязывают значение
thisк контексту внешней функции, т.е. контексту, в котором они были определены. При использовании стрелочных функций не происходит потери контекста.
const obj = {
name: "John",
greet: function () {
setTimeout(() => {
console.log(`Hello, my name is ${this.name}`);
}, 1000);
},
};
obj.greet(); // "Hello, my name is John" (after 1 second delay)- Использование метода
bind()- методbind()создает новую функцию, которая привязывает значениеthisк определенному объекту. Это позволяет сохранить контекст функции, когда она вызывается в другом контексте.
const obj = {
name: "John",
greet: function () {
console.log(`Hello, my name is ${this.name}`);
},
};
const otherObj = {
name: "Jane",
};
const boundGreet = obj.greet.bind(otherObj);
boundGreet(); // "Hello, my name is Jane"- Использование метода
call()илиapply()- методыcall()иapply()вызывают функцию с определенным значениемthis. Разница между этими методами заключается в том, как передаются аргументы функции.
const obj = {
name: "John",
greet: function () {
console.log(`Hello, my name is ${this.name}`);
},
};
const otherObj = {
name: "Jane",
};
obj.greet.call(otherObj); // "Hello, my name is Jane"
obj.greet.apply(otherObj); // "Hello, my name is Jane"- Использование переменной для хранения контекста - можно использовать переменную для хранения контекста, чтобы избежать потери контекста при передаче функции в качестве аргумента.
const obj = {
name: "John",
greet: function () {
console.log(`Hello, my name is ${this.name}`);
},
};
const otherObj = {
name: "Jane",
};
const context = obj;
context.greet(); // "Hello, my name is John"
someFunction(context.greet); // передача метода с сохраненным контекстомЭти способы помогают избежать потери контекста в JavaScript и сохранить значение this в ожидаемом контексте.
- Потеря контекста внутри
setTimeout. Как только метод передаётся отдельно от объекта –thisтеряется.
let user = {
firstName: "Вася",
sayHi() {
alert(`Привет, ${this.firstName}!`);
},
};
setTimeout(user.sayHi, 1000); // Привет, undefined!При запуске этого кода мы видим, что вызов this.firstName возвращает не «Вася», а undefined!
Это произошло потому, что setTimeout получил функцию sayHi отдельно от объекта user (именно здесь функция и потеряла контекст).
Решение 1: Сделать функцию-обёртку
let user = {
firstName: "Вася",
sayHi() {
alert(`Привет, ${this.firstName}!`);
},
};
setTimeout(function () {
user.sayHi(); // Привет, Вася!
}, 1000);Что произойдёт, если до момента срабатывания setTimeout (ведь задержка составляет целую секунду!) в переменную user будет записано другое значение? Тогда вызов неожиданно будет совсем не тот!
Решение 2: Привязать контекст с помощью bind. Без возникновения уязвимости, как в Решении 1.
let user = {
firstName: "Вася",
};
function func() {
alert(this.firstName);
}
let funcUser = func.bind(user);
funcUser(); // Вася