aboutsummaryrefslogtreecommitdiff
path: root/files/ru/web/javascript/reference/operators/this/index.html
blob: 2176ebbdef4dff13c875d20390e5a38ced742000 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
---
title: this
slug: Web/JavaScript/Reference/Operators/this
tags:
  - JavaScript
  - Operator
  - Reference
  - this
  - свойства языка
translation_of: Web/JavaScript/Reference/Operators/this
---
<div>{{jsSidebar("Operators")}}</div>

<p>Поведение ключевого слова <code>this</code> в JavaScript несколько отличается по сравнению с остальными языками. Имеются также различия при использовании <code>this</code> в <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode">строгом</a> и нестрогом режиме.</p>

<p>В большинстве случаев значение <code>this</code> определяется тем, каким образом вызвана функция. Значение <code>this</code> не может быть установлено путем присваивания во время исполнения кода и может иметь разное значение при каждом вызове функции. В ES5 представлен метод {{jsxref('Function.prototype.bind()', 'bind()')}}, который используется для {{jsxref('Operators/this','привязки значения ключевого слова this независимо от того, как вызвана функция','Метод_bind')}}. Также в ES2015 представлены {{jsxref('Functions/Arrow_functions', 'стрелочные функции')}}, которые не создают собственные привязки к <code>this</code> (они сохраняют значение <code>this</code> лексического окружения, в котором были созданы).</p>

<div>{{EmbedInteractiveExample("pages/js/expressions-this.html")}}</div>

<p class="hidden">Исходный код этого интерактивного примера хранится в репозитории на GitHub. Если вы хотите поучаствовать в создании этого интерактивного примера, склонируйте репозиторий про адресу <a href="https://github.com/mdn/interactive-examples">https://github.com/mdn/interactive-examples</a> и присылайте пулреквест.</p>

<h2 id="Синтаксис">Синтаксис</h2>

<pre class="syntaxbox">this</pre>

<h3 id="Значение">Значение</h3>

<p>Свойство контекста выполнения кода (global, function или eval), которое в нестрогом режиме всегда является ссылкой на объект, а в строгом режиме может иметь любое значение.</p>

<h2 id="Global_контекст">Global контекст</h2>

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

<pre class="brush:js">// В браузерах, объект window также является объектом global:
console.log(this === window); // true

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

this.b = "MDN";
console.log(window.b)  // "MDN"
console.log(b)         // "MDN"
</pre>

<div class="blockIndicator note">
<p><strong>Note:</strong> Вы всегда можете легко получить объект global, используя глобальное свойство {{jsxref ("globalThis")}}, независимо от текущего контекста, в котором выполняется ваш код.</p>
</div>

<h2 id="Function_контекст">Function контекст</h2>

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

<h3 id="Простой_вызов">Простой вызов</h3>

<p>Поскольку следующий код не в {{jsxref('Strict_mode', 'строгом режиме')}}, и значение <code>this</code> не устанавливается вызовом, по умолчанию будет использоваться объект global, которым в браузере является <code>{{domxref('window')}}</code>.</p>

<pre class="brush:js">function f1(){
  return this;
}

// В браузере:
f1() === window; // window - глобальный объект в браузере

// В Node:
f1() === global; // global - глобальный объект в Node
</pre>

<p>В строгом режиме, если значение <code>this</code> не установлено в контексте выполнения, оно остается <code>undefined</code>, как показано в следующем примере:</p>

<pre class="brush:js">function f2(){
  "use strict"; // см. strict mode
  return this;
}

f2() === undefined; // true
</pre>

<div class="note">Во втором примере <code>this</code> должно иметь значение <code>{{jsxref("undefined")}}</code>, потому что функция <code>f2</code> была вызвана напрямую, а не как метод или свойство объекта (например, <code>window.f2()</code>). Реализация этой особенности не поддерживалась в некоторых браузерах, когда они впервые начали поддерживать {{jsxref('Strict_mode', 'строгий режим')}}. В результате они некорректно возвращали объект <code>window</code>.</div>

<p>Для того, чтобы при вызове функции установить <code>this</code> в определенное значение, используйте {{jsxref('Function.prototype.call()', 'call()')}} или {{jsxref('Function.prototype.apply()', 'apply()')}}, как в следующих примерах.</p>

<p><strong>Пример 1</strong></p>

<pre dir="rtl"><code>// </code>В качестве первого аргумента методов<code> call или apply</code> может быть передан объект<code>,
// на который будет указывать this.</code><code>
var obj = {a: 'Custom'};

// Это свойство принадлежит глобальному объекту
var a = 'Global';

function whatsThis() {
  return this.a;  //значение this зависит от контекста вызова функции</code>

<code>}

whatsThis();          // 'Global'
whatsThis.call(obj);  // 'Custom'
whatsThis.apply(obj); // 'Custom'</code></pre>

<p><strong>Пример 2</strong></p>

<pre>function add(c, d) {
  return this.a + this.b + c + d;
}

var o = {a: 1, b: 3};

// Первый параметр - это объект для использования в качестве
// 'this', последующие параметры передаются как
// аргументы функции call
add.call(o, 5, 7); // 16

// Первый параметр - это объект для использования в качестве
// 'this', второй - массив, чьи члены используются
// в качестве аргументов функции call
add.apply(o, [10, 20]); // 34
</pre>

<p>Обратите внимание, что в нестрогом режиме, если значение, переданное в <code>call</code> или <code>apply как</code> <code>this</code>, не является объектом, будет сделана попытка преобразовать его в объект с помощью внутренней операции <code>ToObject</code>. Таким образом, если переданное значение является примитивом, таким как <code>7</code> или <code>'foo'</code>, оно будет преобразовано в <code>Object</code> с использованием связанного конструктора, так что примитивное число <code>7</code> будет преобразовано в объект так, как будто с помощью <code>new Number(7)</code>, а строка <code>'foo'</code> - как будто с помощью <code>new String('foo')</code>, например</p>

<pre>function bar() {
  console.log(Object.prototype.toString.call(this));
}

bar.call(7);     // [object Number]
bar.call('foo'); // [object String]
</pre>

<h3 id="Метод_bind">Метод <code>bind</code></h3>

<p>ECMAScript 5 представил {{jsxref("Function.prototype.bind()")}}. Вызов <code>f.bind(someObject)</code> создает новую функцию с тем же телом и областью действия, что и <code>f</code>, но там, где в исходной функции используется <code>this</code>, в новой функции оно постоянно будет связано с первым аргументом <code>bind</code>, независимо от того, как функция используется.</p>

<pre>function f() {
  return this.a;
}

var g = f.bind({a: 'azerty'});
console.log(g()); // azerty

var h = g.bind({a: 'yoo'}); // bind only works once!
console.log(h()); // azerty

var o = {a: 37, f: f, g: g, h: h};
console.log(o.a, o.f(), o.g(), o.h()); // 37,37, azerty, azerty</pre>

<h3 id="Стрелочные_функции">Стрелочные функции</h3>

<p>В {{jsxref('Functions/Arrow_functions', 'стрелочных функциях')}}, <code>this</code> привязан к окружению, в котором была создана функция. В глобальной области видимости <code>this</code> будет указывать на глобальный объект.</p>

<pre><code>var globalObject = this;
var foo = (() =&gt; this);
console.log(foo() === globalObject); // true</code></pre>

<div class="note">
<p>Note: если аргумент this передаётся в call, bind или apply при вызове стрелочной функции, он будет проигнорирован. Вы всё ещё можете добавить аргументы к вызову, но первый аргумент (thisArg) должен быть установлен в null.</p>
</div>

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

<pre><code>// Вызов функции как метода объекта
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</code></pre>

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

<pre><code>// Создаем объект obj, содержащий метод bar, который возвращает функцию,
// которая возвращает свой this. Возвращаемая функция создана
// как стрелочная функция, таким образом её this постоянно замкнут
// на this функции, в которой она создана. </code>Значение bar может быть установлено
<code>//</code> в вызове, который, в свою очередь, устанавливает значение возвращаемой функции.<code>
var obj = { bar : function() {
                    var x = (() =&gt; this);
                    return x;
                  }
          };

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

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

// Но будьте осторожны, если вы ссылаетесь на метод obj, не вызывая его
var fn2 = obj.bar;
// Вызов this стрелочной функции изнутри метода bar вернёт теперь window,
// потому что он следует за this из fn2.
console.log(fn2()() == window); // true</pre>

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

<h3 id="В_методе_объекта">В методе объекта</h3>

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

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

<pre class="brush:js">var o = {
  prop: 37,
  f: function() {
    return this.prop;
  }
};

console.log(o.f()); // logs 37
</pre>

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

<pre class="brush:js">var o = {prop: 37};

function independent() {
  return this.prop;
}

o.f = independent;

console.log(o.f()); // logs 37
</pre>

<p>Эти примеры показывают, что имеет значение только то, что функция была вызвана из свойства <code>f</code> объекта <code>o</code>.</p>

<p>Аналогично, привязывание <code>this</code> обуславливается наличием ближайшей ссылки на объект или свойство. В следующем примере, когда мы вызываем функцию, мы обращаемся к ней как к методу <code>g</code> объекта <code>o.b</code>. На этот раз во время выполнения, <code>this, </code>что находится внутри функции, будет ссылаться на<code> </code> <code>o.b</code>. Тот факт, что объект является членом объекта <code>o</code>, не имеет значения; важна только ближайшая ссылка.</p>

<pre class="brush:js">o.b = {g: independent, prop: 42};
console.log(o.b.g()); // logs 42
</pre>

<h4 id="this_в_цепочке_objects_prototype"><code>this</code> в цепочке object's prototype</h4>

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

<pre class="brush:js">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
</pre>

<p>В этом примере объект, которому присвоена переменная <code>p,</code> не имеет собственного свойства <code>f</code>, а наследует это свойство от своего прототипа. Однако, совершенно неважно, что поиск свойства f в конце концов обнаружит его на объекте <code>o</code>. Поскольку поиск начался с <code>p.f</code>, то и свойство <code>this</code> внутри функции <code>f</code> будет ссылаться на объект <code>p</code>. Таким образом, если <code>f</code> вызывается как метод <code>p</code>, то и <code>this</code> относится к <code>p</code>. Это полезная особенность прототипного наследования JS.</p>

<h4 id="this_с_геттерамисеттерами"><code>this</code> с геттерами/сеттерами</h4>

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

<pre class="brush:js">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
</pre>

<h3 id="В_конструкторе">В конструкторе</h3>

<p>Когда функция используется как конструктор (с ключевым словом <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/new">new</a></code> ), <code>this</code> связано с создаваемым новым объектом.</p>

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

<pre class="brush:js">/*
 * Конструктор работает таким образом:
 *
 * 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
</pre>

<p>В последнем примере (<code>C2</code>), из-за того, что конструктор вернул объект, новый объект, к которому было привязано <code>this</code>, был просто отброшен. (Это фактически делает выражение "<code>this.a = 37;</code>" "мертвым" кодом. Он не является буквально нерабочим, так как он выполняется, но он может быть изъят без каких-либо внешних эффектов.)</p>

<h3 id="call_и_apply"><code>call</code> и <code>apply</code></h3>

<p>Когда в теле функции используется ключевое слово <code>this</code>, его значение может быть привязано к конкретному объекту в вызове при помощи методов <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call">call</a></code> или <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply">apply</a></code>, которые наследуются всеми функциями от <code>Function.prototype</code>.</p>

<pre class="brush:js">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
</pre>

<p>Необходимо отметить, что если методам <code>call</code> и <code>apply</code> передается значение с <code>this</code>, которое не является при этом объектом, будет предпринята попытка конвертировать значение в объект, используя внутреннюю операцию <code>ToObject</code>. Если переданное значение является примитивным типом, например <code>7</code> или <code>'foo'</code>, оно будет преобразовано в объект с использованием родственного конструктора, так примитив <code>7</code> преобразовывается в объект через <code>new Number(7),</code> а строка <code>'foo'</code> в объект через <code>new String('foo'),</code> и т.д.</p>

<pre class="brush:js">function bar() {
  console.log(Object.prototype.toString.call(this));
}

bar.call(7); // [object Number]
</pre>

<h3 id="Как_обработчик_событий_DOM">Как обработчик событий DOM</h3>

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

<pre class="brush:js">// Когда вызывается как слушатель, связанный элемент становится синим
function bluify(e) {
  // Всегда true
  console.log(this === e.currentTarget);
  // true, когда currentTarget и target один объект
  console.log(this === e.target);
  this.style.backgroundColor = '#A5D9F3';
}

// Получить список каждого элемента в документе
var elements = document.getElementsByTagName('*');

// Добавить bluify как слушателя кликов, чтобы при
// нажатии на элемент он становился синим
for (var i = 0; i &lt; elements.length; i++) {
  elements[i].addEventListener('click', bluify, false);
}</pre>

<h3 id="В_инлайновом_обработчике_событий">В инлайновом обработчике событий</h3>

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

<pre class="brush:js">&lt;button onclick="alert(this.tagName.toLowerCase());"&gt;
  Показать this
&lt;/button&gt;
</pre>

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

<pre class="brush:js">&lt;button onclick="alert((function() {return this;} ()));"&gt;
  Показать вложенный this
&lt;/button&gt;
</pre>

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

<h2 id="Спецификации">Спецификации</h2>

<table>
 <tbody>
  <tr>
   <th scope="col">Specification</th>
  </tr>
  <tr>
   <td>{{SpecName('ESDraft', '#sec-this-keyword', 'The this keyword')}}</td>
  </tr>
 </tbody>
</table>

<h2 id="Совместимость">Совместимость</h2>



<p>{{Compat("javascript.operators.this")}}</p>

<h2 id="See_also" name="See_also">Смотри также</h2>

<ul>
 <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode">Строгий режим</a></li>
 <li><a href="http://bjorn.tipling.com/all-this">All this</a>, статья о <code>this</code> в разном контексте</li>
 <li><a href="https://rainsoft.io/gentle-explanation-of-this-in-javascript/">Краткое объяснение ключевого слова 'this' в JavaScript</a></li>
</ul>