Ключевое слово this
1. Контекст исполнения (this)
Можно с уверенностью сказать, что ключевое слово this
является одной из самых запутанных частей JavaScript на старте изучения. Новички часто подставляют this
методом научного тыка до тех пор, пока скрипт не сработает 😐.
Контекст в JavaScript похож на контекст в предложении:
Петя
бежит быстро, потому чтоПетя
пытается поймать поезд.Петя
бежит быстро, потому чтоон
пытается поймать поезд.
Второе предложение звучит лаконичнее. Предметом предложения является Петя и мы можем сказать, что контекст предложения — это Петя, потому что он в центре внимания в это конкретное время в предложении. Даже местоимение кто относится к Пете.
И точно так же объект может быть текущим контекстом исполнения функции.
Обращение к свойствам объекта внутри методов, используя имя самого объекта, аналогично использованию Петя
вместо он
.
У всех функций есть локальная переменная this
. Во время исполнения функции в переменную this
записывается ссылка на объект в контексте которого она вызывается.
this
нам нужен для доступа к методам и свойствам объекта, который вызывает функцию, тем более, что чаще всего имя вызывающего объекта не известно.
2. Правила определения this
Необходимо усвоить всего одно правило для определения this
.
Значение контекста внутри функции определятся не в момент ее создания, а в момент вызова. То есть значение this
определяется тем, как вызывается функция, а не где она была объявлена.
2.1. this в глобальной области видимости
В глобальной области видимости, если скрипт выполняется не в строгом режиме, this
ссылается на объект window
. В строгом режиме значение this
, в глобальной области видимости, будет undefined
.
2.2. this в методе объекта
Если функция была вызвана как метод объекта, то контекст будет ссылаться на объект, частью которого является метод.
Более сложный пример для лучшего понимания:
Сначала создадим функцию в глобальной области видимости и вызовем ее.
После чего присвоим ее в свойство объекта и вызовем как метод этого объекта.
2.3. this в функциях обратного вызова
Когда мы передаем метод, использующий this в качестве параметра, который будет использоваться как функция обратного вызова, будет проблема. Решение этой проблемы рассматривается в следующей секции.
2.4. this в стрелочных функциях
Стрелочные функции не имеют своего this
. В отличии от обычных функций, изменить значение this
внутри стрелки после ее объявления нельзя.
Контекст внутри стрелки определяется местом ее объявления, а не вызова и ссылается на контекст родительской функции.
Стрелочные функции также игнорируют наличие строгого режима. Если стрелка запомнила глобальный контекст, то this
в ней будет содержать ссылку на window
вне зависимости выполняется ли скрипт в строгом режиме или нет.
Ограничивая стрелочные функции постоянным контекстом, JavaScript-движки могут лучше их оптимизировать, в отличие от обычных функций, значение this
которых может быть изменено.
Пример не практичный, но отлично показывает как работает контекст для стрелок. Значение контекста берется из родительской области видимости.
Если привести этот код к ES5, получится следующее.
3. Методы функций call, apply, bind
Присвоение функции в качестве метода объекта может показаться хорошей идеей. Но стоит ли хранить подобные методы? Дублирование уже существующих функций в виде методов объекта будет занимать ресурсы, не принося никаких заметных выгод.
Теперь представьте что у вас 150 отелей и для каждого необходимо выполнить ту же самую операцию при каждом приветствии гостя. Нам, как минимум, хочется сразу вынести этот общий код в функцию.
Функция - это на самом деле довольно хитрый объект, поэтому у нее тоже есть методы. С помощью методов call
и apply
можно выполнить функцию в контексте какого-то объекта, не делая функцию его методом.
3.1. call и аргументы
Запомнить правило использования call
довольно легко: метод call
вызовет функцию fn
передав ее this
ссылку на объект obj
, а также аргументы arg1
, arg2
и т. д.
3.2. apply и аргументы
Метод apply
- полный аналог метода call
за исключением того, что синтаксис вызова аргументов требует не перечисление, а массив.
3.3. bind
Мы рассмотрели случаи, когда необходимо мгновенно вызвать функцию с другим контекстом - для этого используются методы call
и apply
. Но в случае функции обратного вызова, когда необходимо не вызвать функцию на месте, а передать ссылку на эту функцию, причем с привязанным контекстом, call
и apply
не подходят. Метод bind
позволяет решить эту задачу.
Метод bind
создает копию функции fn
с привязанным контекстом obj
и аргументами arg1
, arg2
и так дале, после чего возвращает ее как результат своей работы. В результате мы получаем копию функции с привязанным контекстом, которую можно передать куда угодно и вызвать когда угодно.
Чаще всего метод bind
используется для привязки контекста при передаче методов объекта как функций обратного вызова. Возьмем проблемный пример из предыдущей секции. Задачу привязки контекста мы теперь можем решить используя метод bind
, передав функцией обратного вызова копию метода с привязанным контекстом.
Last updated