this

by 2 contributors:

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

Метки документа и участники

Contributors to this page: wertlex, Mary_Gorgol
Обновлялась последний раз: wertlex,
Скрыть боковую панель