Аналогичным образом, context и this ключевое слово столь же важны и, к сожалению, так же сбивают с толку.

Контекст и this ключевое слово

В JavaScript функции имеют ссылку на контекст их выполнения, что означает способ их вызова. Здесь следует отметить важный нюанс: контекст выполнения функции связан не с тем, как она была объявлена ​​или что функция делает, а о том, как она вызывается в коде. Этот контекст выполнения называется this. Когда вы обращаетесь к this из функции, вы, по сути, получаете доступ к ее контексту выполнения.

Сравните это с лексической областью видимости, которая заботится о том, как функция была объявлена ​​и в каком порядке. Это потому, что решение о том, какая область видимости, принимается во время компиляции, в отличие от context и this, которые происходят динамически при вызове функции.

Различные способы вызова функции

Как упоминалось ранее, контекст зависит от того, как была вызвана функция. Звучит просто - сколько разных способов может быть вызвана функция, не так ли?

Фактически, существует 4 различных способа вызова функции, влияющих на контекст:

  1. Вызов базовой функции.
  2. Вызов функции с объектом контекста, также известный как неявная привязка.
  3. Вызов функции с использованием call() или apply(), также известный как явная привязка.
  4. Путем жесткой привязки значения this с использованием bind().

Давайте посмотрим, как каждый из них влияет на контекст.

1. вызов основных функций

var name = 'aras';

function person () {
    console.log(this.name);
}

person(); // log is 'aras'

В этом примере мы просто вызвали функцию с person() из глобальной области видимости. Следовательно, контекст выполнения функции (т. Е. как она была вызвана) является глобальной областью, а this будет указывать на глобальную область. Поэтому this.name выводит aras.

Тем не менее, если бы мы использовали строгий режим, вставив 'use strict' вверху, this было бы undefined, потому что доступ к this при вызове функции из глобальной области в строгом режиме запрещен. Получать таким образом доступ к глобальной области видимости - плохая практика, и компилятор предполагает, что это не входило в намерения разработчика, и возвращает undefined, чтобы предотвратить побочные эффекты и неприятные ошибки.

2. неявная привязка

Следующий способ вызова функции - через подключенное соединение, то есть с полем объекта. Например, рассмотрим следующий код:

const name = 'aras';

function person () {
    console.log(this.name);
}

const myObject = { person: person, name: 'Natalia' };

myObject.person(); // log is 'Natalia'

В этом примере функция person была вызвана через myObject.person(), который фактически устанавливает контекст выполнения на myObject. Другими словами, как вызывалась функция? Он был вызван из myObject, и на выходе будет Natalia, поскольку this будет указывать на myObject и его name вместо name глобальной области видимости.

3. явное связывание

Вы можете вызвать функцию, используя метод call() или apply(), который очень похож, за исключением параметров, в которых они находятся. Когда функция вызывается через эти имена, мы четко связываем ее реализацию с объектом. Например:

const name = 'aras';

function person () {
    console.log(this.name);
}

const myObject = { person: person, name: 'Natalia' };

person.call(myObject); // log is'Natalia'

call() (или apply()) явно сообщает функции, какой объект использовать как this.

4. жесткая привязка

Явная сила связывания, есть надежный способ жесткого соединения, один объект которого используется в качестве фона, который называется жесткой привязкой соединения. В приведенном выше коде функцию person можно вызвать с любым объектом, используя person.call()и указав объект. Иногда мы должны предотвратить это и убедиться, что person всегда вызывается в одном и том же контексте.

Другими словами, мы можем написать что-то вроде этого:

const name = 'aras';

function person () {
    console.log(this.name);
}

const myObject = { person: person, name: 'Natalia' };

const myNewObject = { person: person, name: 'Viktoria' };

const originalPerson = person;

person = function () {
    originalPerson.call(myObject);
};

person.call(myNewObject); // log is 'Natalia'

Здесь мы предотвратили вызов person с любым контекстом, жестко привязав его к myObject. Это означает, что независимо от того, как вызывается person, this всегда будет равно myObject, поэтому на выходе приведенного выше кода будет Natalia.

Тем не менее, теперь существует гораздо более простой способ достижения жесткого связывания в JavaScript благодаря встроенной функции bind(), представленной в ES5. Процитируем документацию MDN: «метод bind () создает новую функцию, при вызове которой для ключевого слова this установлено заданное значение».

Используя bind(), приведенный выше пример можно переписать следующим образом:

const name = 'aras';

function person () {
    console.log(this.name);
}

const myObject = { person: person, name: 'Natalia' };

const myNewObject = { person: person, name: 'Viktoria' };

person = person.bind(myObject);

person.call(myNewObject); // log is 'Natalia'

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

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