Мы часто используем ключевое слово this в нашем JS-коде, но оно остается одной из наиболее неправильно понимаемых концепций JavaScript. Мы склонны забывать, в какой сфере мы находимся и к чему имеем доступ. Вы когда-нибудь находили ошибку «Cannot read property ‘x’ of undefined» и все время задавались вопросом, почему так, несмотря на правильную инициализацию всех переменных (если нет, сначала сделайте это: p)? В этой статье мы обсудим, как предотвратить эту ошибку с помощью функции привязки.

Недавно в рамках стажировки я много работал над Angular 5 и TypeScript (следовательно, JavaScript) и столкнулся с различными проблемами. Будучи новичком в JavaScript, борясь с ними и обнаруживая, что коллеги довольно часто сталкиваются с похожими проблемами, я решил написать эту серию, чтобы помочь вам сэкономить свое время, если вы сталкиваетесь с аналогичными ошибками :)

Проблема

Мы используем Closures почти везде в нашем коде.
Допустим, у нас есть массив объектов, содержащих products - каждый из которых имеет имя и цену. Теперь мы хотим регистрировать каждый продукт, используя forEachloop, как показано.

Конечно, вы можете захотеть проделать много сложных вещей с каждой записью массива или даже определить собственный компаратор для sort function; вместо того, чтобы просто регистрировать записи. Внутри функции обратного вызова forEach, если мы попытаемся получить доступ к любому из свойств класса Component (что кажется абсолютно нормальным), произойдет следующее:

Это потому, что this в theforEachcallback указывает не на область AppComponent, а на вновь созданную область.

Решение

Вот уловка!

Обратите внимание на привязку в конце определения закрытия. Нам нужно передать требуемое значение thethisparameter в целевую анонимную функцию обратного вызова. Это гдеbind()method появляется на картинке.

Thebind()method создает новую функцию bound, при вызове которой itsthiskeyword устанавливается равным предоставленному значению.

function.bind(thisArg[, arg1[, arg2[, ...]]])

thisArg - это значение, которое будет передано в качествеthisпараметра целевой функции при вызове связанной функции.
arg1, arg2, … - это аргументы, добавляемые к аргументам, предоставленным связанной функции при вызове целевой функции. Эти аргументы (если таковые имеются) затем вставляются в начало аргументов, передаваемых целевой функции, за которыми следуют аргументы, передаваемые связанной функции.
Запутались? Начнем с основ.

Дайвинг глубоко

  • Область действия: Область действия определяет доступность (видимость) переменных. JavaScript имеет область видимости функции: каждая функция создает новую область видимости.
  • Замыкание: Замыкание - это комбинация функции, объединенной (заключенной) со ссылками на ее окружающее состояние (лексическое окружение). Это внутренняя функция, которая имеет доступ к переменным внешней функции.

Я использовал JavaScript в приложении Angular, поэтому this относится к области действия AppComponent (в отличие отwindowobject в чистом приложении JS).
Если мы запускаемconsole.log(this)any где-нибудь внутри вышеуказанного Компонента (конструктора, ngOnInit, и т. д.), он регистрирует объект AppComponent.

Теперь, если мы запустим то же самое внутри функции обратного вызова inforEachloop, this относится к вновь созданной области (которая равна undefined).

Таким образом, когда мы dofunction.bind(this), мы привязываем требуемый контекст к целевой функции, чтобы его можно было использовать внутри нее. Нам нужно выполнять привязку контекста только тогда, когда нам требуется доступ к переменным компонента (в случае приложения Angular) внутри замыканий.

Альтернативы

Этот вариант использования довольно распространен, и есть разные this способы заставить его работать!

  1. Установка значения this вне закрытия
    Мы можем установить переменную this в любую переменную вне анонимной функции обратного вызова, а затем использовать ее внутри.

Но это становится беспорядочным и заполняет код ненужными определениями переменных, таких как self или that.

2. Стрелочные функции
Вместо использования анонимной лямбда-функции мы можем использовать стрелочную функцию. У выражения функции стрелки нет собственного this. На введение стрелочных функций повлияли два фактора: более короткие функции и отсутствие привязки this.

Wohoo! Теперь вы поняли и исправили ошибку.

Надеюсь, это вам помогло! Если да, улыбнитесь и передайте! :)