this в JavaScript
this — это ключевое слово, которое ссылается на тот или иной объект в зависимости от того, где оно записано или как была вызвана функция, где this присутствует.
this или другими словами контекст выполнения — это одна из тем понимание которой необходимо для изучения объектно-ориентированного программирования (ООП) в JavaScript.
Синтаксис
Посмотрим чему равен this с помощью метода console.log()
или запросим значение свойства объекта, предварительно установив его, как this .
В глобальном контексте, за пределами функций this равен объекту window в независимости от того, какой режим разработки установлен строгий ‘use strict’ или нестрогий.
Кстати, уже здесь мы можем обратиться не только к объекту window в целом, но также и к его свойствам.
this в функциях
Если this записывать в отдельной функции, то его значение не всегда равно window . В нестрогом режиме всё без сюрпризов.
В строгом режиме.
Ключевое слово this всегда динамично и указывает на тот объект в контексте которого было вызвано. В примерах выше контекст глобальный оттуда мы и видим window . Кстати, если this записать в функцию, которая лежит внутри другой функции, результат будет таким же.
Методы объекта и this
Теперь рассмотрим другой контекст отличный от глобального.
Вызывая функцию objMethod , как метод объекта student мы видим, что ключевое слово this принимает значение этого объекта, то есть значение того объекта по отношению к которому был вызван этот метод.
Таким образом, мы можем обращаться через this к значениям свойств объекта через их имена. В принципе запись ниже аналогична варианту с this .
Вместо this мы прописываем имя объекта, тем самым также обращаясь к его свойствам. Однако, если мы захотим эту функцию назначить нескольким объектам первый вариант отработает без ошибок в отличие от второго.
Имея в арсенале this нет надобности писать для каждого объекта одну и ту же функцию, в примере мы записали statement() один раз, а далее назначили ее двум разным объектам. При вызове метода для student1 и student2 получили корректный результат.
Работая с this стоит помнить, что ключевое слово определяется в момент вызова функции. Таким образом, если функцию положить в переменную и вызвать уже ее, результат будет отличным.
Стрелочные функции
Стрелочная функция не имеют собственного контекста и если в таком случае прописать this то ссылаться ключевое слово будет на объект ближайший по иерархии. Такая особенность удобна, когда мы хотим передать в функцию внешний контекст.
В первых двух случаях this ссылается на значение объекта student , в свою очередь this , записанная в функции funcWithinFunc , будет равна window .
Функция-конструктор
Функция-конструктор позволяет создавать новые объекты по шаблону на основе других данных. При вызове функции конструктора this принимает значение вновь созданного объекта, который наполняется вследствие выполнения тела функции.
Методы call() и apply()
call() и apply() позволяют явно настроить контекст выполнения функции, результатом работы методов будет выполнение этой функции. Методы идентичны между собой, единственное их различие, это формат в котором записываются аргументы, для call() через запятую, для appy() в массиве.
В первом случае мы определили контекст выполнения функции sayName относительно объекта student1 , во втором относительно student2 и получили в console Степан и Юлия соответственно.
Метод bind()
bind() – это встроенный метод, который также даёт возможность зафиксировать контекст выполнения, чтобы заранее быть уверенным, какое значение будет у this . В отличие от call() и apply() метод bind() возвращает новую функцию, а не вызывает изначальную.
Итого
1. Ключевое слово this позволяет работать с контекстом, получая доступ до объектов, а также имеет в арсенале методы, для того, чтобы менять этот контекст.
2. this не является фиксированным и определяется во время выполнения кода. Таким образом, пока функция не вызвана this не имеет значения.
3. Стрелочные функции не имеют собственного контекста и связываются с ближайшим по иерархии.
4. bind() , call() и apply() — методы позволяющие управлять контекстом.
5. При вызове функции-конструктора this принимает значение вновь созданного объекта.
Ключевое слово this в JavaScript для начинающих
Автор материала, перевод которого мы сегодня публикуем, говорит, что когда она работала в сфере бухучёта, там применялись понятные термины, значения которых легко найти в словаре. А вот занявшись программированием, и, в частности, JavaScript, она начала сталкиваться с такими понятиями, определения которых в словарях уже не найти. Например, это касается ключевого слова this . Она вспоминает то время, когда познакомилась с JS-объектами и функциями-конструкторами, в которых использовалось это ключевое слово, но добраться до его точного смысла оказалось не так уж и просто. Она полагает, что подобные проблемы встают и перед другими новичками, особенно перед теми, кто раньше программированием не занимался. Тем, кто хочет изучить JavaScript, в любом случае придётся разобраться с this . Этот материал направлен на то, чтобы всем желающим в этом помочь.
Что такое this?
Предлагаю вашему вниманию моё собственное определение ключевого слова this . This — это ключевое слово, используемое в JavaScript, которое имеет особое значение, зависящее от контекста в котором оно применяется.
Причина, по которой this вызывает столько путаницы у новичков, заключается в том, что контекст this меняется в зависимости от его использования.
This можно считать динамическим ключевым словом. Мне нравится, как понятие «контекст» раскрыто в этой статье Райана Морра. По его словам, контекст всегда является значением ключевого слова this , которое ссылается на объект, «владеющий» кодом, выполняемым в текущий момент. Однако, тот контекст, который имеет отношение к this , это не то же самое, что контекст выполнения.
Итак, когда мы пользуемся ключевым словом this , мы, на самом деле, обращаемся с его помощью к некоему объекту. Поговорим о том, что это за объект, рассмотрев несколько примеров.
Ситуации, когда this указывает на объект window
Если вы попытаетесь обратиться к ключевому слову this в глобальной области видимости, оно будет привязано к глобальному контексту, то есть — к объекту window в браузере.
При использовании функций, которые имеются в глобальном контексте (это отличает их от методов объектов) ключевое слово this в них будет указывать на объект window .
Попробуйте выполнить этот код, например, в консоли браузера:
Использование this внутри объекта
Когда this используется внутри объекта, это ключевое слово ссылается на сам объект. Рассмотрим пример. Предположим, вы создали объект dog с методами и обратились в одном из его методов к this . Когда this используется внутри этого метода, это ключевое слово олицетворяет объект dog .
This и вложенные объекты
Применение this во вложенных объектах может создать некоторую путаницу. В подобных ситуациях стоит помнить о том, что ключевое слово this относиться к тому объекту, в методе которого оно используется. Рассмотрим пример.
Особенности стрелочных функций
Стрелочные функции ведут себя не так, как обычные функции. Вспомните: при обращении к this в методе объекта, этому ключевому слову соответствует объект, которому принадлежит метод. Однако это не относится к стрелочным функциям. Вместо этого, this в таких функциях относится к глобальному контексту (к объекту window ). Рассмотрим следующий код, который можно запустить в консоли браузера.
Если, озадачившись рассматриваемым вопросом, заглянуть на MDN, там можно найти сведения о том, что стрелочные функции имеют более короткую форму записи, чем функциональные выражения и не привязаны к собственным сущностям this , arguments , super или new.target . Стрелочные функции лучше всего подходят для использования их в роли обычных функций, а не методов объектов, их нельзя использовать в роли конструкторов.
Прислушаемся к MDN и не будем использовать стрелочные функции в качестве методов объектов.
Использование this в обычных функциях
Когда обычная функция находится в глобальной области видимости, то ключевое слово this , использованное в ней, будет привязано к объекту window . Ниже приведён пример, в котором функцию test можно рассматривать в виде метода объекта window .
Однако если функция выполняется в строгом режиме, то в this будет записано undefined , так как в этом режиме запрещены привязки по умолчанию. Попробуйте запустить следующий пример в консоли браузера.
Обращение к this из функции, которая была объявлена за пределами объекта, а потом назначена в качестве его метода
Рассмотрим пример с уже известным нам объектом dog . В качестве метода этого объекта можно назначить функцию chase , объявленную за его пределами. Тут в объекте dog никаких методов не было, до тех пор, пока мы не создали метод foo , которому назначена функция chase . Если теперь вызвать метод dog.foo , то будет вызвана функция chase . При этом ключевое слово this , к которому обращаются в этой функции, указывает на объект dog . А функция chase , при попытке её вызова как самостоятельной функции, будет вести себя неправильно, так как при таком подходе this будет указывать на глобальный объект, в котором нет тех свойств, к которым мы, в этой функции, обращаемся через this .
Ключевое слово new и this
Ключевое слово this находит применение в функциях-конструкторах, используемых для создания объектов, так как оно позволяет, универсальным образом, работать со множеством объектов, создаваемых с помощью такой функции. В JavaScript есть и стандартные функции-конструкторы, с помощью которых, например, можно создавать объекты типа Number или String . Подобные функции, определяемые программистом самостоятельно, позволяют ему создавать объекты, состав свойств и методов которых задаётся им самим.
Как вы уже поняли, мне нравятся собаки, поэтому опишем функцию-конструктор для создания объектов типа Dog , содержащих некоторые свойства и методы.
Когда функцию-конструктор вызывают с использованием ключевого слова new , this в ней указывает на новый объект, который, с помощью конструктора, снабжают свойствами и методами.
Вот как можно работать со стандартными конструкторами JavaScript.
Теперь поработаем с только что созданной функцией-конструктором Dog .
Вот ещё один пример использования функций-конструкторов.
О важности ключевого слова new
При вызове функции-конструктора с использованием ключевого слова new ключевое слово this указывает на новый объект, который, после некоторой работы над ним, будет возвращён из этой функции. Ключевое слово this в данной ситуации весьма важно. Почему? Всё дело в том, что с его помощью можно, используя единственную функцию-конструктор, создавать множество однотипных объектов.
Это позволяет нам масштабировать приложение и сокращать дублирование кода. Для того чтобы понять важность этого механизма, подумайте о том, как устроены учётные записи в социальных сетях. Каждая учётная запись может представлять собой экземпляр объекта, создаваемый с помощью функции-конструктора Friend . Каждый такой объект можно заполнять уникальными данными о пользователе. Рассмотрим следующий код.
Итоги
На самом деле, особенности использования ключевого слова this в JavaScript не ограничиваются вышеописанными примерами. Так, в череду этих примеров можно было бы включить использование функций call , apply и bind . Так как материал этот рассчитан на начинающих и ориентирован на разъяснение основ, мы их здесь не касаемся. Однако если сейчас у вас сформировалось начальное понимание this , то и с этими методами вы вполне сможете разобраться. Главное — помните о том, что если что-то с первого раза понять не удаётся, не прекращайте учиться, практикуйтесь, читайте материалы по интересующей вас теме. В одном из них вам обязательно попадётся нечто такое (какая-то удачная фраза, например), что поможет понять то, что раньше понять не удавалось.
Уважаемые читатели! Возникали ли у вас сложности с пониманием ключевого слова this в JavaScript?
Урок №121. Скрытый указатель *this
Один из частых вопросов, которые новички задают по поводу классов: «При вызове метода класса, как C++ отслеживает то, какой объект его вызвал?». Ответ заключается в том, что C++ для этих целей использует скрытый указатель *this!
Скрытый указатель *this
Ниже приведен простой класс, который содержит целочисленное значение и имеет конструктор и функции доступа. Обратите внимание, деструктор здесь не нужен, так как язык C++ может очистить память после переменной-члена самостоятельно:
Результат выполнения программы:
При вызове another.setNumber(4); C++ понимает, что функция setNumber() работает с объектом another , а m_number — это фактически another.m_number . Рассмотрим детально, как это всё работает.
Возьмем, к примеру, следующую строку:
Хотя на первый взгляд кажется, что у нас здесь только один аргумент, но на самом деле у нас их два! Во время компиляции строка another.setNumber(4); конвертируется компилятором в следующее:
Теперь это всего лишь стандартный вызов функции, а объект another (который ранее был отдельным объектом и находился перед точкой) теперь передается по адресу в качестве аргумента функции.
Но это только половина дела. Поскольку в вызове функции теперь есть два аргумента, то и метод нужно изменить соответствующим образом (чтобы он принимал два аргумента). Следовательно, следующий метод:
Конвертируется компилятором в:
При компиляции обычного метода, компилятор неявно добавляет к нему параметр *this. Указатель *this — это скрытый константный указатель, содержащий адрес объекта, который вызывает метод класса.
Есть еще одна деталь. Внутри метода также необходимо обновить все члены класса (функции и переменные), чтобы они ссылались на объект, который вызывает этот метод. Это легко сделать, добавив префикс this-> к каждому из них. Таким образом, в теле функции setNumber(), m_number (переменная-член класса) будет конвертирована в this->m_number . И когда *this указывает на адрес another , то this->m_number будет указывать на another.m_number .
Соединяем всё вместе:
При вызове another.setNumber(4) компилятор фактически вызывает setNumber(&another, 4) .
Внутри setNumber() указатель *this содержит адрес объекта another .
К любым переменным-членам внутри setNumber() добавляется префикс this-> . Поэтому, когда мы говорим m_number = number , компилятор фактически выполняет this->m_number = number , который, в этом случае, обновляет another.m_number на number .
Хорошей новостью является то, что это всё происходит скрыто от нас (программистов), и не имеет значения, помните ли вы, как это работает или нет. Всё, что вам нужно запомнить — все обычные методы класса имеют указатель *this, который указывает на объект, связанный с вызовом метода класса.
Указатель *this всегда указывает на текущий объект
Начинающие программисты иногда путают, сколько указателей *this существует. Каждый метод имеет в качестве параметра указатель *this, который указывает на адрес объекта, с которым в данный момент выполняется операция, например:
Ключевое слово this
Пример первый — у переменной экземпляра и метода одинаковые имена
Допустим, у нас есть класс Human , для которого определено поле «имя»: Найдите вероятность того что в помещении