Потеря контекста (this) происходит, когда значение this внутри функции не ссылается на ожидаемый объект. Это может произойти, если функция вызывается в контексте, который не является объектом, или если функция передается как обычная функция, а не как метод объекта.

Существует несколько способов, которые можно использовать для избежания потери контекста:

  1. Использование стрелочных функций - стрелочные функции привязывают значение 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)
  1. Использование метода 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"
  1. Использование метода 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"
  1. Использование переменной для хранения контекста - можно использовать переменную для хранения контекста, чтобы избежать потери контекста при передаче функции в качестве аргумента.
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 в ожидаемом контексте.

  1. Потеря контекста внутри 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(); // Вася

Назад