diff options
Diffstat (limited to 'files/uk/web/javascript/reference/operators/this/index.html')
-rw-r--r-- | files/uk/web/javascript/reference/operators/this/index.html | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/files/uk/web/javascript/reference/operators/this/index.html b/files/uk/web/javascript/reference/operators/this/index.html new file mode 100644 index 0000000000..8f0d159cda --- /dev/null +++ b/files/uk/web/javascript/reference/operators/this/index.html @@ -0,0 +1,408 @@ +--- +title: this +slug: Web/JavaScript/Reference/Operators/this +tags: + - JavaScript + - this + - Оператор + - ключове слово +translation_of: Web/JavaScript/Reference/Operators/this +--- +<div>{{jsSidebar("Operators")}}</div> + +<p><strong>Ключове слово функції <code>this</code></strong> поводиться дещо інакше у JavaScript у порівнянні з іншими мовами. Воно також має певні відмінності між <a href="/uk/docs/Web/JavaScript/Reference/Strict_mode">строгим</a> та нестрогим режимами.</p> + +<p>У більшості випадків, значення <code>this</code> визначається тим, як викликається функція (прив'язка під час виконання). Воно не може бути переприсвоєне під час виконання, і може змінюватись кожен раз, коли викликається функція. ES5 запровадив метод {{jsxref("Function.prototype.bind()", "bind()")}} для <a href="#Метод_bind">присвоєння значення this у функції незалежно від того, як вона викликається</a>, а ES2015 запровадив <a href="/uk/docs/Web/JavaScript/Reference/Functions/Стрілкові_функції">стрілкові функції</a>, які не мають власної прив'язки <code>this</code> (вони зберігають значення <code>this</code> оточуючого лексичного контексту).</p> + +<div>{{EmbedInteractiveExample("pages/js/expressions-this.html")}}</div> + + + +<h2 id="Синтаксис">Синтаксис</h2> + +<pre class="syntaxbox">this</pre> + +<h3 id="Значення">Значення</h3> + +<p>Властивість контексту виконання (глобального, функції чи eval), яка, у нестрогому режимі завжди посилається на об'єкт, а у строгому режимі може бути будь-яким значенням.</p> + +<h2 id="Глобальний_контекст">Глобальний контекст</h2> + +<p>У глобальному контексті виконання (поза межами будь-яких функцій) <code>this</code> посилається на глобальний об'єкт, як у строгому, так і у нестрогому режимі.</p> + +<pre class="brush:js">// У веб-переглядачах об'єкт window також є глобальним об'єктом: +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>Заувага:</strong> Ви завжди легко можете отримати глобальний об'єкт за допомогою глобальної властивості {{jsxref("globalThis")}}, незалежно від поточного контексту, у якому виконується ваш код.</p> +</div> + +<h2 id="Контекст_функції">Контекст функції</h2> + +<p>Всередині функції значення <code>this</code> залежить від того, як викликається функція.</p> + +<h3 id="Простий_виклик">Простий виклик</h3> + +<p>Оскільки наступний код не є кодом у <a href="/uk/docs/Web/JavaScript/Reference/Strict_mode">строгому режимі</a>, і тому, що значення <code>this</code> не було присвоєне викликом, <code>this</code> за замовчуванням дорівнюватиме глобальному об'єкту, яким у переглядачі є {{domxref("Window", "window")}}. </p> + +<pre class="brush:js">function f1() { + return this; +} + +// У переглядачі: +f1() === window; // true + +// У Node: +f1() === global; // true</pre> + +<p>Однак, у строгому режимі значення <code>this</code> не присвоюється при вході у контекст виконання, воно залишається <code>undefined</code>, як показано у наступному прикладі<strong>:</strong></p> + +<pre class="brush:js">function f2() { + 'use strict'; // дивіться строгий режим + return this; +} + +f2() === undefined; // true +</pre> + +<div class="note">У другому прикладі <code>this</code> має дорівнювати {{jsxref("undefined")}}, тому що функція <code>f2</code> була викликана прямо, а не як метод чи властивість об'єкта (наприклад, <code>window.f2()</code>). Ця функціональність не була реалізована у деяких переглядачах, коли вони вперше почали підтримувати <a href="/uk/docs/Web/JavaScript/Reference/Strict_mode" title="Strict mode">строгий режим</a>. Як результат, вони неправильно повертали об'єкт <code>window</code>.</div> + +<p>Для присвоєння <code>this</code> певного значення під час виклику функції використовуйте {{jsxref("Function.prototype.call()", "call()")}} або {{jsxref("Function.prototype.apply()", "apply()")}}, як у наступних прикладах<strong>.</strong></p> + +<p><strong>Приклад 1</strong></p> + +<pre class="brush:js" dir="rtl">// Об'єкт може бути переданий першим аргументом у call чи apply, і буде прив'язаний до this. +var obj = {a: 'Користувацький'}; + +// Ця властивість створена у глобальному об'єкті +var a = 'Глобальний'; + +function whatsThis() { + return this.a; // Значення this залежить від того, як викликається функція +} + +whatsThis(); // 'Глобальний' +whatsThis.call(obj); // 'Користувацький' +whatsThis.apply(obj); // 'Користувацький' +</pre> + +<p><strong>Приклад 2</strong></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); // 16 + +// Перший параметр - це об'єкт для використання в якості +// 'this', другий - це масив, чиї елементи +// використовуються як аргументи для виклику функції +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>, вона буде загорнута у Object за допомогою відповідного конструктора, а отже, просте число <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] +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>this</code> прив'язано до першого аргументу <code>bind</code>, незалежно від того, як використовується функція.</p> + +<pre class="brush:js">function f() { + return this.a; +} + +var g = f.bind({a: 'привіт'}); +console.log(g()); // привіт + +var h = g.bind({a: 'йо'}); // bind працює лише один раз! +console.log(h()); // привіт + +var o = {a: 37, f: f, g: g, h: h}; +console.log(o.a, o.f(), o.g(), o.h()); // 37,37, привіт, привіт +</pre> + +<h3 id="Стрілкові_функції">Стрілкові функції</h3> + +<p>У <a href="/uk/docs/Web/JavaScript/Reference/Functions/Стрілкові_функції">стрілкових функціях</a> <code>this</code> зберігає значення <code>this</code> оточуючого лексичного контексту. У глобальному коді йому буде присвоєно глобальний об'єкт:</p> + +<pre class="brush: js">var globalObject = this; +var foo = (() => this); +console.log(foo() === globalObject); // true</pre> + +<div class="note"> +<p><strong>Заувага</strong>: якщо this передається як аргумент до call, bind чи apply під час виклику стрілкової функції, він буде проігнорований. Ви все одно можете подавати аргументи до call, але перший аргумент (thisArg) має бути null.</p> +</div> + +<pre class="brush: js">// Виклик в якості методу об'єкта +var obj = {func: foo}; +console.log(obj.func() === globalObject); // true + +// Спроба встановити this за допомогою call +console.log(foo.call(obj) === globalObject); // true + +// Спроба встановити this за допомогою bind +foo = foo.bind(obj); +console.log(foo() === globalObject); // true</pre> + +<p>Що б не відбувалось, <code>this</code> у <code>foo</code> дорівнює значенню, встановленому під час створення (у наведеному вище прикладі, глобальному об'єкту). Те саме стосується стрілкових функцій, створених всередині інших функцій: їхнє значення <code>this</code> залишиться таким, як у оточуючому лексичному контексті.</p> + +<pre class="brush: js">// Створюємо obj з методом bar, який вертає функцію, що +// повертає своє значення this. Повернена функція створена як +// стрілкова функція, а отже, її this прив'язується до +// this оточуючої функції. Можна присвоювати значення bar +// під час виклику, що в свою чергу присвоїть значення +// поверненої функції. +var obj = { + bar: function() { + var x = (() => this); + return x; + } +}; + +// Викликаємо bar як метод obj, встановлюючи obj значенням його this +// Присвоюємо посилання на повернену функцію у fn +var fn = obj.bar(); + +// Виклик fn без присвоєння this мав би присвоїти +// за замовчуванням глобальний об'єкт або undefined у строгому режимі +console.log(fn() === obj); // true + +// Але будьте обережні, якщо посилаєтесь на метод obj, не викликаючи його +var fn2 = obj.bar; +// Виклик this стрілкової функції зсередини методу bar +// тепер поверне window, бо він бере this з fn2. +console.log(fn2()() == window); // true +</pre> + +<p>У наведеному коді функція (назвемо її анонімною функцією А), присвоєна <code>obj.bar</code>, повертає іншу функцію (назвемо її анонімною функцією Б), яка створюється як стрілкова функція. В результаті <code>this</code> функції Б незмінно дорівнює <code>this</code> з <code>obj.bar</code> (функції A) під час виклику. Коли викликається повернена функція (функція Б), її <code>this</code> завжди дорівнюватиме початково присвоєному значенню. У наведеному прикладі <code>this</code> функції Б присвоюється значення <code>this</code> функції А, яке дорівнює <code>obj</code>, отже, воно залишається рівним <code>obj</code>, навіть коли викликається таким способом, який мав би присвоїти <code>this</code> значення <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()); // 37 +</pre> + +<p>Зауважте, що на цю поведінку зовсім не впливає те, як і де була визначена функція. У попередньому прикладі ми визначили функцію <code>f</code> вбудованою, як член об'єкта, під час визначення <code>o</code>. Однак, ми так само легко могли спочатку визначити функцію, а потім додати її до <code>o.f</code>. Це призводить до такої самої поведінки:</p> + +<pre class="brush:js">var o = {prop: 37}; + +function independent() { + return this.prop; +} + +o.f = independent; + +console.log(o.f()); // 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>o.b</code>. Той факт, що сам об'єкт є членом об'єкта <code>o</code>, не має наслідків; все, що має значення, це найближче посилання.</p> + +<pre class="brush:js">o.b = {g: independent, prop: 42}; +console.log(o.b.g()); // 42 +</pre> + +<h4 id="this_у_ланцюжку_прототипів_обєкта"><code>this</code> у ланцюжку прототипів об'єкта</h4> + +<p>Такий самий принцип діє для методів, визначених десь у ланцюжку прототипів об'єкта. Якщо метод присутній у ланцюжку прототипів об'єкта, <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>, він успадковує її від свого прототипу. Але не має значення, що пошук <code>f</code> зрештою знаходить властивість з таким ім'ям у <code>o</code>; пошук починався як посилання на <code>p.f</code>, а отже, <code>this</code> всередині функції приймає значення об'єкта, на який посилається <code>p</code>. Тобто, оскільки <code>f</code> викликається як метод <code>p</code>, його <code>this</code> посилається на <code>p</code>. Це цікава особливість прототипного наслідування JavaScript.</p> + +<h4 id="this_з_гетером_або_сетером"><code>this</code> з гетером або сетером</h4> + +<p>Знову ж таки, цей самий принцип діє, коли функція викликається з гетера чи сетера. У функції, що використовується в якості гетера чи сетера, <code>this</code> прив'язується до об'єкта, де властивість отримується чи встановлюється.</p> + +<pre class="brush:js">function sum() { + return this.a + this.b + this.c; +} + +var o = { + a: 1, + b: 2, + c: 3, + get average() { + return (this.a + this.b + this.c) / 3; + } +}; + +Object.defineProperty(o, 'sum', { + get: sum, enumerable: true, configurable: true}); + +console.log(o.average, o.sum); // 2, 6 +</pre> + +<h3 id="Як_конструктор">Як конструктор</h3> + +<p>Коли функція використовується як конструктор (з ключовим словом {{jsxref("Operators/new", "new")}}), її <code>this</code> прив'язується до нового об'єкта, що створюється.</p> + +<div class="note"> +<p>Хоча за замовчуванням конструктор повертає об'єкт, на який посилається <code>this</code>, він може, натомість, повернути якийсь інший об'єкт (якщо значення, що повертається, не є об'єктом, тоді повертається об'єкт <code>this</code>).</p> +</div> + +<pre class="brush:js">/* + * Конструктори працюють так: + * + * function MyConstructor(){ + * // Тут розташований код тіла функції. + * // Створюємо бажані властивості |this| + * // присвоєнням. Наприклад, + * this.fum = "nom"; + * // і так далі... + * + * // Якщо функція має оператор return, який + * // повертає об'єкт, цей об'єкт буде + * // результатом виразу |new|. Інакше, + * // результатом виразу буде поточний об'єкт, + * // прив'язаний до |this| + * // (найбільш розповсюджений варіант). + * } + */ + +function C() { + this.a = 37; +} + +var o = new C(); +console.log(o.a); // 37 + + +function C2() { + this.a = 37; + return {a: 38}; +} + +o = new C2(); +console.log(o.a); // 38 +</pre> + +<p>У останньому прикладі (<code>C2</code>), через те, що під час створення був повернений об'єкт, новий об'єкт, до якого було прив'язано <code>this</code>, просто відкидається. (Це, по суті, робить інструкцію "<code>this.a = 37;</code>" мертвим кодом. Він не абсолютно мертвий, бо він виконується, але його можна видалити без жодних наслідків для зовнішнього коду.)</p> + +<h3 id="Як_обробник_подій_у_DOM">Як обробник подій у DOM</h3> + +<p>Коли функція використовується як обробник подій, її значенням <code>this</code> встановлюється елемент, який запустив подію (деякі переглядачі не дотримуються цієї конвенції для прослуховувачів, доданих динамічно іншими методами, ніж {{domxref("EventTarget.addEventListener()", "addEventListener()")}}).</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'; +} + +// Отримати список усіх елементів у document +var elements = document.getElementsByTagName('*'); + +// Додати bluify як прослуховувач події натискання, щоб, коли +// на елемент натискають, він ставав синім +for (var i = 0; i < elements.length; i++) { + elements[i].addEventListener('click', bluify, false); +}</pre> + +<h3 id="У_вбудованому_обробнику_подій">У вбудованому обробнику подій</h3> + +<p>Коли код викликається з вбудованого <a href="/uk/docs/Web/Guide/Events/Event_handlers">обробника подій</a>, значенням його <code>this</code> встановлюється DOM-елемент, де розташований прослуховувач:</p> + +<pre class="brush: html"><button onclick="alert(this.tagName.toLowerCase());"> + Показати this +</button> +</pre> + +<p>Наведене оповіщення показує <code>button</code>. Однак, зауважте, що лише у зовнішньому коді <code>this</code> присвоюється таким чином:</p> + +<pre class="brush: html"><button onclick="alert((function() { return this; })());"> + Показати this внутрішньої функції +</button> +</pre> + +<p>У цьому випадку, <code>this</code> внутрішньої функції не присвоюється, тому функція повертає глобальний об'єкт/window (тобто, об'єкт за замовчуванням у нестрогому режимі, де <code>this</code> не встановлюється викликом).</p> + +<h2 id="Специфікації">Специфікації</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">Специфікація</th> + <th scope="col">Статус</th> + <th scope="col">Коментар</th> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-this-keyword', 'The this keyword')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES2015', '#sec-this-keyword', 'The this keyword')}}</td> + <td>{{Spec2('ES2015')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-11.1.1', 'The this keyword')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES3', '#sec-11.1.1', 'The this keyword')}}</td> + <td>{{Spec2('ES3')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES1', '#sec-11.1.1', 'The this keyword')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>Початкове визначення. Реалізоване у JavaScript 1.0.</td> + </tr> + </tbody> +</table> + +<h2 id="Сумісність_з_веб-переглядачами">Сумісність з веб-переглядачами</h2> + + + +<p>{{Compat("javascript.operators.this")}}</p> + +<h2 id="Див._також">Див. також</h2> + +<ul> + <li><a href="/uk/docs/Web/JavaScript/Reference/Strict_mode">Строгий режим</a></li> + <li><a href="https://dmitripavlutin.com/gentle-explanation-of-this-in-javascript/">Лагідне роз'яснення ключового слова 'this' у JavaScript</a></li> + <li>Отримання глобального контексту: {{jsxref("globalThis")}}</li> +</ul> |