# Context (this)

Поведение ключевого слова `this` в JavaScript несколько отличается от остальных языков. Имеются также различия при использовании `this` в [строгом](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode) и нестрогом режиме.

В большинстве случаев значение `this` определяется тем, каким образом вызвана функция. Значение `this`не может быть установлено путем присваивания во время исполнения кода и может иметь разное значение при каждом вызове функции. В ES5 представлен метод [`bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind), чтобы [определить значение ключевого слова this независимо от того, как вызвана функция](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this$translate?tolocale=ru#The_bind_method). Также в ECMAScript 2015 представлены [стрелочные функции](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Functions/Arrow_functions), this которых привязан к окружению, в котором была создана стрелочная функция.

## Глобальный контекст <a href="#globalnyi_kontekst" id="globalnyi_kontekst"></a>

В глобальном контексте выполнения (за пределами каких-либо функций)`this` ссылается на глобальный объект вне зависимости от использования в строгом или нестрогом режиме.

```javascript
console.log(this.document === document); // true

// В браузерах, объект window также является глобальным:
console.log(this === window); // true

this.a = 37;
console.log(window.a); // 37
```

## В контексте функции <a href="#v_kontekste_funkcii" id="v_kontekste_funkcii"></a>

В пределах функции значение `this` зависит от того, каким образом вызвана функция.

### Простой вызов <a href="#prostoi_vyzov" id="prostoi_vyzov"></a>

В этом случае значение `this` не устанавливается вызовом. Так как этот код написан не в строгом режиме, значением `this` всегда должен быть объект, по умолчанию - глобальный объект.

```javascript
function f1(){
  return this;
}
// В браузере
f1() === window; // window глобальный объект в браузере
```

В строгом режиме, значение `this` остается тем значением, которое было установлено в контексте исполнения. Если такое значение не определено, оно остается undefined.

```javascript
function f2(){
  "use strict"; // see strict mode
  return this;
}

f2() === undefined;
```

Итак, в строгом режиме, если this не определено, оно остается не определено.

Для того, чтобы передать значение this от одного контекста другому, необходимо использовать [call](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call) или [apply](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Function/apply).

### Стрелочные функции <a href="#strelochnye_funkcii" id="strelochnye_funkcii"></a>

В [стрелочных функциях](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Functions/Arrow_functions) `this` привязан к окружению, в котором была создана функция. В глобальной области видимости `this` будет указывать на глобальный объект.

```javascript
var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true
```

Неважно, как функция `foo()`будет вызвана, ее this будет указывать на глобальный объект.`this` будет сохранять свое значение, даже если функция `foo()`будет вызвана как метод объекта (что в обычных функциях связывает `this` с объектом вызова) или с использованием методов `call`,`apply ,`или`bind`:

```javascript
// Вызов функции как метода объекта
var obj = {foo: foo};
console.log(obj.foo() === globalObject); // true

// Попытка установить this с помощью call
console.log(foo.call(obj) === globalObject); // true

// Попытка установить this с помощью bind
foo = foo.bind(obj);
console.log(foo() === globalObject); // true
```

Независимо от этого, `this` функции `foo()`имеет тоже значение, что и при создании функции (глобальный объект в примере выше). То же самое касается стрелочных функций, созданных внутри других функций: их `this` будет привязан к окружению.

```javascript
// Создаем объект obj с методом bar, который возвращает функцию
// которая возвращает свой this. Возвращаемая функция создана
// как стрелочная функция, таким образом ее this замкнут 
// на this функции, в которой она создана. 
var obj = { bar : function() {
                    var x = (() => this);
                    return x;
                  }
          };

// Вызываем bar как метод объекта obj, устанавливая его this на obj
// Присваиваем ссылку возвращаемой функции fn
var fn = obj.bar();

// Вызываем fn без установки this, что в обычных функциях указывало бы
// на глобальный объект или undefined в строгом режиме.
console.log(fn() === obj); // true
```

В примере выше, функция (назовем ее анонимной функцией A), присвоенная `obj.bar` , возвращает другую функцию (назовем ее анонимной функцией B), которая создана как стрелочная функция. В результате вызова функции A, `this функции B замкнут на this,` принадлежащий `obj.bar` (функции A). `this` функции B, всегда будет иметь то значение, которое он получил при создании. В примере выше `this функции B` указывает на `this функции A, который указывает на` obj, таким образом this будет указывать на `obj` даже когда будет вызван методом, который в нормальных условиях устанавливал значение this равным `undefined или глобальному объекту` ( или любым другим методом, как в предыдущих примерах).

### В методе объекта <a href="#v_metode_obekta" id="v_metode_obekta"></a>

Когда функция вызывается как метод объекта, используемое в этой функции ключевое слово `this` принимает значение объекта, по отношению к которому вызван метод.

В следующем примере, когда вызвано свойство `o.f()`, внутри функции `this` привязано к объекту `o.`

```javascript
var o = {
  prop: 37,
  f: function() {
    return this.prop;
  }
};

console.log(o.f()); // logs 37
```

Необходимо отметить, что на поведение this совсем не влияет то, как или где была определена функция. В предыдущем примере мы определили функцию внутри свойства `f` во время определения объекта `o`. Однако мы могли бы также просто определить сначала функцию, а затем закрепить ее за за свойством `o.f`. В этом случае поведение this не изменится:

```javascript
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` , не имеет значения; важна только ближайшая ссылка.

```javascript
o.b = {g: independent, prop: 42};
console.log(o.b.g()); // logs 42
```

#### `this`в цепочке object's prototype <a href="#this_v_cepochke_objects_prototype" id="this_v_cepochke_objects_prototype"></a>

Это же представление справедливо и для методов, определенных где-либо в цепочке object's prototype. Если метод находится в цепочке прототипов, то this ссылается на объект, на котором был вызван метод, т.е. так, словно метод является методом самого объекта, а не прототипа.

```javascript
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`с геттерами/сеттерами <a href="#this_s_getteramisetterami" id="this_s_getteramisetterami"></a>

Все те же утверждения справедливы, если функция вызывается из геттера или сеттера. Для функции, которая используется как геттер или сеттер, `this` привязан к объекту, свойство которого необходимо извлечь через геттер/сеттер.

```javascript
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
```

### В конструкторе <a href="#v_konstruktore" id="v_konstruktore"></a>

Когда функция используется как конструктор (с ключевым словом [`new`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new)), `this` связано с создаваемым новым объектом.

Примечание: по умолчанию конструктор возвращает объект, к которому ссылается `this`, но он может вернуть и другой объект (если возвращаемое значение не является объектом, тогда будет возвращен объект с `this`).

```javascript
/*
 * Контруктор работает таким образом:
 *
 * 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` <a href="#call_i_apply" id="call_i_apply"></a>

Когда в теле функции используется ключевое слово `this`, его значение может быть привязано к конкретному объекту в вызове при помощи методов [`call`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call) или[`apply`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply), которые наследуются всеми функциями от `Function.prototype`.

```javascript
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')` и т.д.

```javascript
function bar() {
  console.log(Object.prototype.toString.call(this));
}

bar.call(7); // [object Number]
```

### Метод `bind` <a href="#metod_bind" id="metod_bind"></a>

ECMAScript 5 ввел [`Function.prototype.bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind). Вызов `f.bind(someObject)`создает новую функцию с тем же телом и областью видимости, что и `f`, но там, где находится `this` в исходной функции, в новой функции существует постоянная привязка к первому аргументу метода `bind`несмотря на то, как используется данная функция.

```javascript
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 <a href="#kak_obrabotchik_sobytii_dom" id="kak_obrabotchik_sobytii_dom"></a>

Когда функция используется как обработчик событий, `this` присваивается элементу, с которого начинается событие (некоторые браузеры не следуют этому соглашению для слушателей, добавленных динамически с помощью всех методов кроме`addEventListener`).

```javascript
// 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);
}
```

### В инлайновом обработчике событий <a href="#v_inlainovom_obrabotchike_sobytii" id="v_inlainovom_obrabotchike_sobytii"></a>

Когда код вызван из инлайнового обработчика, this указывает на DOM-элемент, в котором расположен код события:

```
<button onclick="alert(this.tagName.toLowerCase());">
  Показать this
</button>
```

Код выше выведет '`button`'. Следует отметить, this будет указывать на DOM элемент только во внешних (не вложенных) функциях:

```
<button onclick="alert((function(){return this}()));">
  Показать вложенный this
</button>
```

В этом случае `this` вложеной функции не будет установлен, так что будет возвращен global/window объект.
