Context (this)
Поведение ключевого слова this в JavaScript несколько отличается от остальных языков. Имеются также различия при использовании this в строгом и нестрогом режиме.
В большинстве случаев значение this определяется тем, каким образом вызвана функция. Значение thisне может быть установлено путем присваивания во время исполнения кода и может иметь разное значение при каждом вызове функции. В ES5 представлен метод bind, чтобы определить значение ключевого слова this независимо от того, как вызвана функция. Также в ECMAScript 2015 представлены стрелочные функции, this которых привязан к окружению, в котором была создана стрелочная функция.
Глобальный контекст
В глобальном контексте выполнения (за пределами каких-либо функций)this ссылается на глобальный объект вне зависимости от использования в строгом или нестрогом режиме.
console.log(this.document === document); // true
// В браузерах, объект window также является глобальным:
console.log(this === window); // true
this.a = 37;
console.log(window.a); // 37В контексте функции
В пределах функции значение this зависит от того, каким образом вызвана функция.
Простой вызов
В этом случае значение this не устанавливается вызовом. Так как этот код написан не в строгом режиме, значением this всегда должен быть объект, по умолчанию - глобальный объект.
function f1(){
return this;
}
// В браузере
f1() === window; // window глобальный объект в браузереВ строгом режиме, значение this остается тем значением, которое было установлено в контексте исполнения. Если такое значение не определено, оно остается undefined.
Итак, в строгом режиме, если this не определено, оно остается не определено.
Для того, чтобы передать значение this от одного контекста другому, необходимо использовать call или apply.
Стрелочные функции
В стрелочных функциях this привязан к окружению, в котором была создана функция. В глобальной области видимости this будет указывать на глобальный объект.
Неважно, как функция foo()будет вызвана, ее this будет указывать на глобальный объект.this будет сохранять свое значение, даже если функция foo()будет вызвана как метод объекта (что в обычных функциях связывает this с объектом вызова) или с использованием методов call,apply ,илиbind:
Независимо от этого, this функции foo()имеет тоже значение, что и при создании функции (глобальный объект в примере выше). То же самое касается стрелочных функций, созданных внутри других функций: их this будет привязан к окружению.
В примере выше, функция (назовем ее анонимной функцией A), присвоенная obj.bar , возвращает другую функцию (назовем ее анонимной функцией B), которая создана как стрелочная функция. В результате вызова функции A, this функции B замкнут на this, принадлежащий obj.bar (функции A). this функции B, всегда будет иметь то значение, которое он получил при создании. В примере выше this функции B указывает на this функции A, который указывает на obj, таким образом this будет указывать на obj даже когда будет вызван методом, который в нормальных условиях устанавливал значение this равным undefined или глобальному объекту ( или любым другим методом, как в предыдущих примерах).
В методе объекта
Когда функция вызывается как метод объекта, используемое в этой функции ключевое слово this принимает значение объекта, по отношению к которому вызван метод.
В следующем примере, когда вызвано свойство o.f(), внутри функции this привязано к объекту o.
Необходимо отметить, что на поведение this совсем не влияет то, как или где была определена функция. В предыдущем примере мы определили функцию внутри свойства f во время определения объекта o. Однако мы могли бы также просто определить сначала функцию, а затем закрепить ее за за свойством o.f. В этом случае поведение this не изменится:
Эти примеры показывают, что имеет значение только то, что функция была вызвана из свойства f объекта o.
Аналогично, привязывание this обуславлавливается наличием ближайшей ссылки на объект или свойство. В следующем примере, когда мы вызываем функцию, мы обращаемся к ней как к методу g объекта o.b. На этот раз во время выполнения this, что находится внутри функции, будет ссылаться на o.b. Тот факт, что объект является членом объекта o , не имеет значения; важна только ближайшая ссылка.
thisв цепочке object's prototype
thisв цепочке object's prototypeЭто же представление справедливо и для методов, определенных где-либо в цепочке object's prototype. Если метод находится в цепочке прототипов, то this ссылается на объект, на котором был вызван метод, т.е. так, словно метод является методом самого объекта, а не прототипа.
В этом примере, объект, которому присвоена переменная p, не имеет собственного свойства f, а наследует это свойство от своего прототипа. Однако совершенно неважно, что поиск свойства f в конце концов обнаружит его на объекте o. Поскольку поиск начался с p.f, то и свойство this внутри функции fбудет ссылаться на объектp. Таким образом, если f вызывается как метод p, то и this относится к p. Это полезная особенность прототипного наследования JS.
thisс геттерами/сеттерами
thisс геттерами/сеттерамиВсе те же утверждения справедливы, если функция вызывается из геттера или сеттера. Для функции, которая используется как геттер или сеттер, this привязан к объекту, свойство которого необходимо извлечь через геттер/сеттер.
В конструкторе
Когда функция используется как конструктор (с ключевым словом new), this связано с создаваемым новым объектом.
Примечание: по умолчанию конструктор возвращает объект, к которому ссылается this, но он может вернуть и другой объект (если возвращаемое значение не является объектом, тогда будет возвращен объект с this).
В последнем примере (C2) из-за того, что конструктор вернул объект, новый объект, к которому было привязано this, был просто отброшен. (Это фактически делает выражение "this.a = 37;" "мертвым" кодом. Он не является буквально нерабочим, так как он выполняется, но он может быть изъят без каких-либо внешних эффектов.)
callиapply
callиapplyКогда в теле функции используется ключевое слово this, его значение может быть привязано к конкретному объекту в вызове при помощи методов call илиapply, которые наследуются всеми функциями от Function.prototype.
Необходимо отметить, что если методам call и apply передается значение с this, которое не является при этом объектом, будет предпринята попытка конвертировать значение в объект, используя внутреннюю операцию ToObject. Если переданное значение является примитивным типом, таким как 7 или 'foo', оно будет преобразовано в объект с использованием родственного конструктора, так примитив 7 преобразовывается в объект через new Number(7), а строка 'foo' в объект через new String('foo') и т.д.
Метод bind
bindECMAScript 5 ввел Function.prototype.bind. Вызов f.bind(someObject)создает новую функцию с тем же телом и областью видимости, что и f, но там, где находится this в исходной функции, в новой функции существует постоянная привязка к первому аргументу метода bindнесмотря на то, как используется данная функция.
Как обработчик событий DOM
Когда функция используется как обработчик событий, this присваивается элементу, с которого начинается событие (некоторые браузеры не следуют этому соглашению для слушателей, добавленных динамически с помощью всех методов кромеaddEventListener).
В инлайновом обработчике событий
Когда код вызван из инлайнового обработчика, this указывает на DOM-элемент, в котором расположен код события:
Код выше выведет 'button'. Следует отметить, this будет указывать на DOM элемент только во внешних (не вложенных) функциях:
В этом случае this вложеной функции не будет установлен, так что будет возвращен global/window объект.
Last updated