Легко забыть правила, определяющие, на что указывает ключевое слово JavaScript this в различных сценариях. Данный мини-справочник предназначен для того, чтобы быстро освежить знания и справиться с различными задачами.

Почти всегда при работе с контекстом функции используется this, и самое главное, что необходимо помнить - если this используется в глобальном контексте, то это глобальный объект (window в браузере и global в Node.js).

Четыре правила

Значение this отличается в зависимости от того, как вызывается функция, поэтому мы не можем узнать значение this, просто посмотрев на саму функцию; нам нужно знать контекст, в котором вызывается функция.

Следует помнить о 4 правилах. Быстро пробежимся по ним.

Простой вызов функции

this - это глобальный объект в нестрогом режиме и undefined в строгом режиме.

В случае простого вызова функции в нестрогом режиме по умолчанию будет использоваться глобальный объект:

function car() {
  console.log(this.bmw);
}
car();  // => undefined

var bmw = 'BMW';
car();  // => 'BMW'

С тем же сценарием, но в строгом режиме this будет undefined.

'use strict'
function car() {
  console.log(this.bmw);
}
car();  // Ошибка TypeError

var bmw = 'BMW';
car();  // => Ошибка TypeError

Также следует помнить, что переменные, объявленные с помощью let или const на глобальном уровне, сохраняются не в глобальном объекте, а вместо этого в недоступной декларативной записи, поэтому наш предыдущий пример выдаст нам другой результат при использовании let:

function car() {
  console.log(this.bmw);
}
car();  // => undefined

let bmw = 'BMW';
car();  // => undefined

window.bmw = 'BMW';
car();  // => 'BMW'

Неявная привязка

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

Это правило будет применяться в большинстве случаев в вашем повседневном коде при вызове метода объекта:

let myDog = {
  name: 'Шарик',
  voice: 'Гав!!',
  dog: function () {
    console.log(this.voice);
  }
}

myDog.dog();  // => 'Гав!!'

Обратите внимание, что мы получим тот же результат, если наш объект содержит только ссылку на функцию:

function dog() {
  console.log(this.voice);
}
let myDog = {
  name: 'Шарик',
  voice: 'Гав!!',
  dog: dog
}

myDog.dog();  // => 'Гав!!'

Явная привязка

Мы можем явно указать движку JavaScript определить this необходимым значением, используя call, apply или bind.

call и apply могут использоваться для вызова функции с определенным значением this:

function dog() {
  console.log(this.voice);
}
let myDog = {
  name: 'Шарик',
  voice: 'Гав!!',
}

dog.call(myDog);  // => 'Гав!!'

Оба метода call и apply выполняют одну и ту же задачу, и первым аргументом для обоих должно быть this. Разница между ними только для случая, если вызываемой функции необходимо передать дополнительные аргументы. При вызове call дополнительные аргументы передаются как обычный список аргументов, разделенных запятыми, а при apply передается массив аргументов.

bind используется для создания новой функции, постоянно привязанной к значению this. В следующем примере мы создаем новую функцию, у которой this постоянно привязан к myDog и переопределяем dog с уже новой постоянно привязанной функцией:

function dog() {
  console.log(this.voice);
}
let myDog = {
  name: 'Шарик',
  voice: 'Гав!!',
}
dog = dog.bind(myDog)

dog();  // => 'Гав!!'

Привязка с помощью new

Использование ключевого слова new создает новый объект, и this указывает на него.

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

function Dog(name) {
  this.name = name;
}
let myDog = new Dog('Шарик');

console.log(myDog.name);  // 'Шарик'

Бонусное правило - стрелочная функция

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

В примере this в стрелочной функции имеет то же значение, что и this в включающей его функции Dog:

function Dog(voice) {
  this.voice = voice;
  this.voiceUpperCase = () => {
    return this.voice.toUpperCase();
  }
}
const myDog = new Dog('Гав!!');

console.log(myDog.voice);  // 'Гав!!'
console.log(myDog.voiceUpperCase());  // ГАВ!!