diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:42:52 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:42:52 -0500 |
commit | 074785cea106179cb3305637055ab0a009ca74f2 (patch) | |
tree | e6ae371cccd642aa2b67f39752a2cdf1fd4eb040 /files/ru/web/javascript/reference/operators/this/index.html | |
parent | da78a9e329e272dedb2400b79a3bdeebff387d47 (diff) | |
download | translated-content-074785cea106179cb3305637055ab0a009ca74f2.tar.gz translated-content-074785cea106179cb3305637055ab0a009ca74f2.tar.bz2 translated-content-074785cea106179cb3305637055ab0a009ca74f2.zip |
initial commit
Diffstat (limited to 'files/ru/web/javascript/reference/operators/this/index.html')
-rw-r--r-- | files/ru/web/javascript/reference/operators/this/index.html | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/files/ru/web/javascript/reference/operators/this/index.html b/files/ru/web/javascript/reference/operators/this/index.html new file mode 100644 index 0000000000..cfd5ae4385 --- /dev/null +++ b/files/ru/web/javascript/reference/operators/this/index.html @@ -0,0 +1,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 = (() => 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 = (() => 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 < elements.length; i++) { + elements[i].addEventListener('click', bluify, false); +}</pre> + +<h3 id="В_инлайновом_обработчике_событий">В инлайновом обработчике событий</h3> + +<p>Когда код вызван из инлайнового обработчика, <code>this</code> указывает на DOM элемент, в котором расположен код события:</p> + +<pre class="brush:js"><button onclick="alert(this.tagName.toLowerCase());"> + Показать this +</button> +</pre> + +<p>Код выше выведет '<code>button</code>'. Следует отметить, что <code>this</code> будет указывать на DOM элемент только во внешних (не вложенных) функциях:</p> + +<pre class="brush:js"><button onclick="alert((function() {return this;} ()));"> + Показать вложенный this +</button> +</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> |