Как изменить контекст (`this`) в JavaScript?

«Как изменить контекст (`this`) в JavaScript?» — вопрос из категории JavaScript, который задают на 26% собеседований Node.js Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В JavaScript значение this определяется тем, как вызывается функция, а не тем, где она объявлена. Изменить его можно явно несколькими способами.

1. Явный вызов с помощью call(), apply() и bind(): Эти методы доступны у всех функций.

  • func.call(thisArg, arg1, arg2, ...) Вызывает функцию с заданным контекстом thisArg и аргументами, переданными индивидуально.

    function greet(greeting, punctuation) {
      console.log(`${greeting}, ${this.name}${punctuation}`);
    }
    
    const person = { name: 'Alice' };
    greet.call(person, 'Hello', '!'); // Вывод: Hello, Alice!
  • func.apply(thisArg, [argsArray]) Аналогичен call(), но аргументы передаются в виде массива (или array-like объекта).

    const args = ['Hi', '?'];
    greet.apply(person, args); // Вывод: Hi, Alice?

    Полезно, когда количество аргументов неизвестно заранее.

  • func.bind(thisArg, arg1, arg2, ...) Создает новую функцию, которая при вызове будет иметь заданный контекст this. Аргументы, переданные в bind, будут подставлены первыми.

    const boundGreet = greet.bind(person, 'Hey');
    boundGreet('...'); // Вывод: Hey, Alice...
    // Контекст person зафиксирован

    bind() часто используется для фиксации контекста в колбэках (например, в обработчиках событий).

2. Особенности стрелочных функций: Стрелочные функции не имеют своего this. Они лексически захватывают значение this из окружающей их области видимости. Методы call(), apply(), bind() не работают для изменения их контекста.

const obj = {
  value: 'My Value',
  regularFunc: function() {
    console.log(this.value); // 'My Value' (this = obj)
  },
  arrowFunc: () => {
    console.log(this.value); // undefined (this берется из внешней области, например, global)
  }
};

const newContext = { value: 'New Value' };
obj.regularFunc.call(newContext); // 'New Value' (контекст изменен)
obj.arrowFunc.call(newContext);   // undefined (контекст НЕ изменен)

3. Ключевое слово new: При вызове функции с оператором new создается новый объект, и this внутри этой функции-конструктора ссылается на этот новый объект.

function Car(model) {
  this.model = model; // this указывает на новый экземпляр
}
const myCar = new Car('Tesla');
console.log(myCar.model); // 'Tesla'

Итог: Для явного управления контекстом используйте call/apply для немедленного вызова или bind для создания новой функции с фиксированным контекстом. Выбирайте обычные функции, когда нужен динамический this, и стрелочные — когда нужно сохранить контекст родительской функции.