Освойте «это» в JavaScript

В этой статье мы рассмотрим очень важную, но столь запутанную тему в JavaScript, а именно ключевое слово «this».

Если вас пугает «это», не волнуйтесь! Мы узнаем, как определить значение ключевого слова «this», используя пять простых правил.

Эти пять простых правил заключаются в следующем:

  • Обычный —привязка по умолчанию
  • Функция внутри объектаНеявная привязка
  • Заимствование функцийЯвное связывание
  • Использование функции для создания объектовНовая привязка
  • Чем функция стрелки отличается от обычной —лексическая привязка

Не беспокойтесь об этих страшных именах. Люди, занимающиеся информатикой, любят называть термины так, чтобы они звучали как инопланетяне. Под капотом это просто общие понятия, которые может понять любой желающий человек.

Переменная this соответствует тому, как вы вызываете функцию. Эти правила помогают нам определить значение this в различных сценариях.

Как только вы поймете эти правила, вы больше не будете их бояться.

Что такое «это» вкратце

В JavaScript при каждом вызове функции движок JavaScript создает новый контекст выполнения. Этот контекст выполнения существует до тех пор, пока функция не завершит выполнение. Каждый контекст выполнения содержит переменную с именем this.

#Правило 1. Привязка по умолчанию

При вызове функции стандартным способом, показанным выше, «this» на самом деле будет ссылаться на глобальный объект!

В браузере глобальный объект означает объект Window.

Следует помнить одно исключение — это когда включен строгий режим. Написав «use-strict», вы можете предотвратить объявление чего-либо в глобальном объекте.

#Правило 2. Неявное связывание

Если функция содержится в объекте, то на этот объект будет ссылаться «этот».

Для приведенного выше ключевое слово this будет указывать на personObj

#Правило 3. Явное связывание

Мы видели, как this указывает на глобальный объект, а в другом случае указывает на объект, который его содержит. Разве не было бы неплохо иметь возможность контролировать, чем станет эта переменная при вызове функции?

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

Давайте разберемся на примере.

Предположим, у нас есть два объекта, скажем, personObj и readerObj.

Оба объекта имеют свойство имени. У personObj есть функция, которая может печатать значение внутри name, но у readerObj нет такой функции!

Здесь мы можем использовать один из трех методов — call, apply или bind.

Этот процесс называется заимствованием функций.

Мы позаимствовали метод sayName для readerObj.

Теперь мы можем вывести свойство имени, которое находится в readerObj.

Мы вызываем метод sayName из personObj, но в то же время мы сообщаем движку JavaScript, что переменная this в методе sayName должна указывать на readerObj.

Поэтому, когда механизм JavaScript выполняет код, переменная this в функции sayName указывает не на personObj, а на readerObj.

Имеет ли это смысл?

Не только это — мы также можем передавать некоторые аргументы, когда используем функцию call.

Мы передали Намасте в качестве аргумента

Мы можем использовать аргумент в методе sayName.

Когда мы выполним код, мы получим вывод вместе с переданным аргументом.

Метод apply работает так же, но вместо обычных аргументов принимает в качестве аргумента массив.

Точно так же работает и метод bind — он может принимать обычный аргумент.

Но в отличие от call и apply — bind возвращает функцию — эту функцию можно сохранить в переменной и выполнить в будущем.

Можно увидеть использование bind в каррировании функций — тема, которую мы рассмотрим в будущем.

#Правило 4. Новая привязка

Мы используем ключевое слово new для создания экземпляра или копии объекта. Ключевое слово new делает следующее:

  • Он создает пустой объект, а затем указывает ключевому слову this, чтобы он указывал на этот пустой объект.
  • Затем он добавляет оператор return this в конец этой функции.

Помните, что когда экземпляр объекта создается с использованием ключевого слова new, «this» всегда указывает на этот вновь созданный экземпляр.

Давайте разберемся в этом на примере.

Когда мы запускаем этот код, что мы должны получить?

Как мы сказали — пустой объект!

Что происходит под капотом

Какие? Мы вызываем функцию?

Да!

Видите, я сказал вам, что его вызывают.

Давайте посмотрим на все это.

Если мы поместим какое-то значение в функцию, она поместит его во вновь созданный объект, а затем вернет его!

Когда мы console.log(newPersonObj)

Давайте завершим эту концепцию анимацией.

Так как dev.to поддерживает анимацию только в 500 кадров, прикрепляю внешнюю ссылку на анимацию
Перейти за анимацией

В приведенном выше примере мы используем функцию для создания объекта.

Этот тип функции известен как конструктор функции.

Помните, в newPersonObj, где хранится копия personObj, переменная this указывает на пустое personObj

Имеет ли это смысл сейчас?

Хорошо! Давайте теперь разберемся с последним правилом.

#Правило 5. Лексическое связывание

С появлением ES6 — у нас появились стрелочные функции. Стрелочные функции с их ультратонким синтаксисом являются естественной заменой их традиционным анонимным аналогам.

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

Стрелочные функции аналогичны обычным анонимным функциям, за одним важным исключением — поведением этого объекта внутри функции.

В обычной функции значение «this» зависит от контекста — вызовите функцию внутри ссылки, а «this» указывает на объект ссылки; вызовите его внутри еще одной функции, такой как setInterval(), тогда 'this' указывает на глобальный объект окна.

Например, в следующем примере делается попытка вызвать метод start() пользовательского объекта для увеличения его свойства счетчика на 1 каждую секунду, но это не удается из-за неправильного предположения о счетчике ссылок на объект 'this'.

В приведенном выше примере this.counter неправильно ссылается на свойство счетчика объекта countup, хотя ошибка может быть не так очевидна. Можно ошибочно или небрежно предположить, что 'this' указывает на объект countup, хотя на самом деле он указывает на глобальный объект window из-за контекста 'this', который вызывается внутри глобального метода окна setInterval().

Результатом является ссылка на несуществующее свойство window.counter, которое будет постоянно возвращать NaN при попытке увеличить его. Чтобы правильно сослаться на countup объект, а затем внутри анонимной функции, мы должны кэшировать ссылку на правильный объект 'this' до того, как контекст изменится на другой:

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

Сравните это с обычными функциями, где «this» является динамическим и зависит от контекста, в котором он вызывается, независимо от области действия на момент определения «this».

Давайте возьмем предыдущий пример, который поначалу доставил нам проблемы, и посмотрим, как переход на использование стрелочной функции интуитивно решает проблему:

Мы решили проблему, просто используя функцию стрелки.

Вывод

Если вы поняли все правила, то похлопайте себя по спине — вы это заслужили! Теперь вы больше не боитесь самой запутанной концепции JavaScript — ключевого слова «this».

В этой статье мы узнали:

  • При вызове функции стандартным способом, показанным выше, «this» фактически будет относиться к глобальному объекту!
  • Если функция содержится в объекте, то «это» будет указывать на этот объект.
  • call, apply и bind — это функции, доступны нам с помощью JavaScript, чтобы изменить поведение «this» в нашей программе.
  • Ключевое слово или оператор new при использовании создает пустой объект, а затем указывает «this», чтобы он указывал на вновь созданный объект
  • Функция стрелки позволяет нам лексически связать ключевое слово «this» в программе, что означает, что его значение статично и определяется местом, где находится ключевое слово «this». определенный.