This translation is incomplete. Please help translate this article from English.
Сводка
Поведение ключевого слово this в JavaScript несколько отличается по сравнению с остальными языками. Имеются также различия при использовании this в строгом и нестрогом режиме.
В большинстве случаев значение this определяется тем, каким образом вызвана функция. Значение this не может быть установлено путем присваивания во время исполнения кода, и может иметь разное значение при каждом вызове функции .В ES5 представлен метод bind ,чтобы определить значение ключевого слова this в зависимости от того, как оно вызвано.
Синтаксис
this
Глобальный контекст
В глобальном контексте выполнения (за пределами каких-либо функций), this ссылается на глобальный объект вне зависимости от использования в строгом или нестрогом режиме.
console.log(this.document === document); // true // В браузерах, объект window также является глобальным: console.log(this === window); // true this.a = 37; console.log(window.a); // 37
В контексте функции
В пределах функции значение this зависит от того, каким образом вызвана функция.
Простой вызов
function f1(){
return this;
}
f1() === window; // global object
В этом случае значение this не устанавливается вызовом. Так как этот код написан не в строгом режиме, значением this всегда должен быть объект, по умолчанию - глобальный объект.
function f2(){
"use strict"; // see strict mode
return this;
}
f2() === undefined;
В строгом режиме, значение this остается тем значением, которое было установлено в контексте исполнения. Если такое значение не определено, оно остается undefined. Оно может быть установлено любым значением: null или 42 или "Я не this".
this должно иметь значение undefined, потому что функция f2 была вызвана без ссылки на какую-либо основу (например, window.f2()). Реализация этой особенности не поддерживалась в некоторых браузерах, в то время когда они уже начали поддерживать строгий режим. В результате они некорректно возвращали объект window.В методе объекта
Когда функция вызывается как метод объекта, используемое в этой функции ключевое слово this принимает значение объекта, по отношению к которому вызнан метод.
В следующем примере, когда вызвано свойство o.f() , внутри функции this привязано к объекту o.
var o = {
prop: 37,
f: function() {
return this.prop;
}
};
console.log(o.f()); // logs 37
Необходимо отметить, что на поведение this совсем не влияет то, как или где была определена функция. В предыдущем примере мы определили функцию внутри свойства f во время определения объекта o. Однако, мы могли бы также просто определить сначала функцию, а затем закрепить ее за за свойством o.f. В этом случае поведение this не изменится:
var o = {prop: 37};
function independent() {
return this.prop;
}
o.f = independent;
console.log(o.f()); // logs 37
Эти примеры показывают, что имеет значение только то, что функция была вызвана из свойства f объекта o.
Аналогично, привязывание this обуславлавливается наличием ближайшей ссылки на объект или свойство. В следующем примере, когда мы вызываем функцию, мы обращаемся к ней как к методу g объекта o.b. На этот раз во время выполнения, this, что находится внутри функции, будет ссылаться на o.b. Тот факт, что объект является членом объекта o не имеет значения; важна только ближайшая ссылка.
o.b = {g: independent, prop: 42};
console.log(o.b.g()); // logs 42
this в цепочке object's prototype
Это же представление справедливо и для методов, определенных где-либо в цепочке object's prototype. Если метод находится в цепочке прототипов, то this ссылается на объект, на котором был вызван метод, т.е. так, словно метод является методом самого объекта, а не прототипа.
var o = {f:function(){ return this.a + this.b; }};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5
В этом примере, объект, которому присвоена переменная p, не имеет собственного свойства f, а наследует это свойство от своего прототипа. Однако, совершенно неважно, что поиск свойства f в конце концов обнаружит его на объекте o. Поскольку поиск начался с p.f, то и свойство this внутри функции f будет ссылаться на объект p. Таким образом, если f вызывается как метод p, то и this относится к p. Это полезная особеность прототипного наследования JS.
this с геттерами/сеттерами
Все те же утверждения справедливы, если функция вызывается из геттера или сеттера. Для функции, которая используется как геттер или сеттер this привязан к объекту, свойство которого необходимо извлечь через геттер/сеттер.
function modulus(){
return Math.sqrt(this.re * this.re + this.im * this.im);
}
var o = {
re: 1,
im: -1,
get phase(){
return Math.atan2(this.im, this.re);
}
};
Object.defineProperty(o, 'modulus', {
get: modulus, enumerable:true, configurable:true});
console.log(o.phase, o.modulus); // logs -0.78 1.4142
В конструкторе
Когда функция используется как конструктор (с ключевым словом new ), this связано с создаваемым новым объектом.
Примечание: по умолчанию конструктор возвращает объект, к которому ссылается this, но он может вернуть и другой объект (если возвращаемое значение не является объектом, тогда будет возвращен объект с this).
/*
* Контруктор работает таким образом:
*
* function MyConstructor(){
* // фактический код, составляющий тело функции.
* // создание свойств с |this| по
* // желанию, определяя их. например,
* this.fum = "nom";
* // и т.д..
*
* // Если функция возвращает выражение,
* // возвращающее объект, этот объект будет
* // результатом выражения|new|. В обратном случае,
* // результат выражения - объект
* // в данный момент привязанный к |this|
* // (т.е. наиболее часто встречающийся случай).
* }
*/
function C(){
this.a = 37;
}
var o = new C();
console.log(o.a); // logs 37
function C2(){
this.a = 37;
return {a:38};
}
o = new C2();
console.log(o.a); // logs 38
В последнем примере (C2), из-за того, что конструктор вернул объект, новый объект, к которому было привязано this был просто отброшен. (Это фактически делает выражение "this.a = 37;" "мертвым" кодом. Он не является буквально нерабочим,так как он выполняется, но он может быть изъят без каких-либо внешних эффектов.)
call и apply
Когда в теле функции используется ключевое слово this , его значение может быть привязано к конкретному объекту в вызове при помощи методов call or apply ,которые наследуются всеми функциями от Function.prototype.
function add(c, d){
return this.a + this.b + c + d;
}
var o = {a:1, b:3};
// Первый параметр - это объект, который следует использовать как
// 'this', последующие параметры передаются
// как аргументы при вызове функции
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
// Первый параметр - объект, который следует использовать как
// 'this', второй параметр - массив,
// элементы которого используются как аргументы при вызове функции
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34
Необходимо отметить,что если методам call и apply, передается значение с this, которое не явдяется при этом объектом, будет предпринята попытка конвертировать значение в объект , используя внутреннюю операцию ToObject. Если переданное значение является примитивным типом, таким как 7 или 'foo', оно будет преобразовано в объект с использованием родственного конструктора, так примитив 7 преобразовывается в объект через new Number(7), а строка 'foo' в объект через new String('foo'), и т.д.
function bar() {
console.log(Object.prototype.toString.call(this));
}
bar.call(7); // [object Number]
Метод bind
ECMAScript 5 ввел Function.prototype.bind. Вызов f.bind(someObject) создает новую функцию с тем же телом и областью видимости что и f, но там, где находится this в исходной функции, в новой функции существует постоянная привязка к первому аргументу метода bind, несмотря на то, как используется данная функция.
function f(){
return this.a;
}
var g = f.bind({a:"azerty"});
console.log(g()); // azerty
var o = {a:37, f:f, g:g};
console.log(o.f(), o.g()); // 37, azerty
Как обработчик событий DOM
Когда функция используется как обработчик событий, this приваивается элементу с которого начинается событие (некоторые браузеры не следуют этому соглашению для слушателей добавленных динамически с помощью всех методов кроме addEventListener).
// When called as a listener, turns the related element blue
function bluify(e){
// Always true
console.log(this === e.currentTarget);
// true when currentTarget and target are the same object
console.log(this === e.target);
this.style.backgroundColor = '#A5D9F3';
}
// Get a list of every element in the document
var elements = document.getElementsByTagName('*');
// Add bluify as a click listener so when the
// element is clicked on, it turns blue
for(var i=0 ; i<elements.length ; i++){
elements[i].addEventListener('click', bluify, false);
}
In an in–line event handler
When code is called from an in–line handler, its this is set to the DOM element on which the listener is placed:
<button onclick="alert(this.tagName.toLowerCase());"> Show this </button>
The above alert shows button. Note however that only the outer code has its this set this way:
<button onclick="alert((function(){return this}()));">
Show inner this
</button>
In this case, the inner function's this isn't set so it returns the global/window object (i.e. the default object in non–strict mode where this isn't set by the call).
Specifications
| Specification | Status | Comment |
|---|---|---|
| ECMAScript 1st Edition. | Standard | Initial definition. Implemented in JavaScript 1.0 |
| ECMAScript 5.1 (ECMA-262) Определение 'The this keyword' в этой спецификации. |
Стандарт | |
| ECMAScript 2015 (6th Edition, ECMA-262) Определение 'The this keyword' в этой спецификации. |
Стандарт |
Browser compatibility
| Feature | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari |
|---|---|---|---|---|---|
| Basic support | (Да) | (Да) | (Да) | (Да) | (Да) |
| Feature | Android | Chrome for Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
|---|---|---|---|---|---|---|
| Basic support | (Да) | (Да) | (Да) | (Да) | (Да) | (Да) |
See also
- Строгий режим
- All this, an article about
thisin different contexts