aboutsummaryrefslogtreecommitdiff
path: root/files/uk/web/javascript/reference/global_objects/function/apply/index.html
blob: 78183d8102e04418c4b3df657b38f4ac6b4414cf (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
---
title: Function.prototype.apply()
slug: Web/JavaScript/Reference/Global_Objects/Function/apply
tags:
  - Function
  - JavaScript
  - Довідка
  - Функція
  - метод
translation_of: Web/JavaScript/Reference/Global_Objects/Function/apply
---
<div>{{JSRef}}</div>

<p>Метод <code><strong>apply()</strong></code> викликає функцію із заданим значенням <code>this</code> та аргументами, переданими у вигляді масиву (або <a href="/uk/docs/Web/JavaScript/Guide/Indexed_collections#Working_with_array-like_objects">подібного до масиву об'єкта</a>).</p>

<div class="note">
<p><strong>Заувага:</strong> Хоча синтаксис цієї функції є майже ідентичним до синтаксису {{jsxref("Function.call", "call()")}}, фундаментальна відмінність полягає в тому, що метод <code>call()</code> приймає <strong>список аргументів</strong>, тоді як метод <code>apply()</code> приймає <strong>єдиний масив аргументів</strong>.</p>
</div>

<div class="blockIndicator note">
<p><strong>Заувага:</strong> Коли першим аргументом є undefined або null, схожий результат можна отримати за допомогою <a href="/uk/docs/Web/JavaScript/Reference/Operators/Spread_syntax">оператора розпакування</a> масивів.</p>
</div>

<p>{{EmbedInteractiveExample("pages/js/function-apply.html")}}</p>

<div class="hidden">
<p>The source for this interactive example is stored in a GitHub repository. If you'd like to contribute to the interactive examples project, please clone <a href="https://github.com/mdn/interactive-examples">https://github.com/mdn/interactive-examples</a> and send us a pull request.</p>
</div>

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

<pre class="syntaxbox"><var>function</var>.apply(<var>thisArg, </var>[<var>argsArray</var>])</pre>

<h3 id="Параметри">Параметри</h3>

<dl>
 <dt><code>thisArg</code></dt>
 <dd>Значення <code>this</code>, передане для виклику у функцію <em><code>function</code></em>. Зазначте, що <code>this</code> може не бути фактичним значенням, яке бачить метод: якщо метод є функцією не у {{jsxref("Strict_mode", "строгому режимі", "", 1)}}, {{jsxref("null")}} та {{jsxref("undefined")}} будуть замінені глобальним об'єктом, а прості значення будуть запаковані. Цей аргумент є обов'язковим.</dd>
 <dt><code>argsArray</code></dt>
 <dd>Необов'язковий. Подібний до масиву об'єкт, що визначає аргументи, з якими функція має бути викликана, або {{jsxref("null")}} чи {{jsxref("undefined")}}, якщо жодних аргументів не має бути передано у функцію. Починаючи з ECMAScript 5, ці аргументи можуть бути загальними подібними до масиву об'єктами замість масиву. Дивіться нижче інформацію щодо {{anch("Сумісність_з_веб-переглядачами", "сумісності з веб-переглядачами")}}.</dd>
</dl>

<h3 id="Значення_яке_повертається">Значення, яке повертається</h3>

<p>Результат виконання функції з вказаним значенням <code><strong>this</strong></code> та аргументами.</p>

<h2 id="Опис">Опис</h2>

<p>Ви можете присвоїти інший об'єкт <code>this</code>, коли викликаєте існуючу функцію. <code>this</code> посилається на поточний об'єкт, з якого здійснюється виклик. З <code>apply</code> ви можете написати метод один раз, а потім успадковувати його в іншому об'єкті, без необхідності переписувати метод для нового об'єкта.</p>

<p>Метод <code>apply</code> дуже схожий на {{jsxref("Function.call", "call()")}}, за виключенням типу аргументів, які він підтримує. Ви використовуєте масив аргументів замість списку аргументів (параметрів). З методом <code>apply</code> ви також можете використовувати літерал масиву, для прикладу, <code><em>func</em>.apply(this, ['їсти', 'банани'])</code>, або об'єкт {{jsxref("Array")}}, для прикладу, <code><em>func</em>.apply(this, new Array('їсти', 'банани'))</code>.</p>

<p>Ви також можете використати об'єкт {{jsxref("Functions/arguments", "arguments")}} як параметр <code>argsArray</code>. <code>arguments</code> - локальна змінна функції. Вона може використовуватись для всіх не заданих аргументів об'єкта, який викликається. Таким чином, вам не потрібно знати аргументи об'єкта, що викликається, коли ви використовуєте метод <code>apply</code>. Ви можете скористатись об'єктом <code>arguments,</code> щоб передати усі аргументи. Далі об'єкт, який викликається, відповідає за обробку аргументів.</p>

<p>З появою 5-ї версії ECMAScript, ви також можете використовувати будь-який подібний до масиву об'єкт, отже, на практиці це означає, що він має поле <code>length</code> та цілі числа в якості параметрів у діапазоні <code>(0...length-1)</code>. Як приклад, ви тепер можете використати {{domxref("NodeList")}} або власноруч написаний об'єкт виду <code>{ 'length': 2, '0': 'їсти', '1': 'банани' }</code>.</p>

<div class="note">
<p>Чимало більш старих переглядачів, в тому числі Chrome &lt;17 та Internet Explorer &lt;9, не приймають подібні до масиву об'єкти і викидатимуть виняток.</p>
</div>

<h2 id="Приклади">Приклади</h2>

<h3 id="Використання_apply_для_додавання_масиву_до_іншого_масиву">Використання <code>apply</code> для додавання масиву до іншого масиву</h3>

<p>Ми можемо використати метод <code>push</code>, щоб додати елемент до масиву. І, оскільки <code>push</code> приймає змінну кількість аргументів, ми також можемо додати кілька елементів за раз. Але, якщо ми передамо у <code>push</code> масив, він додасть, власне, масив єдиним елементом, замість того, щоб додати окремі елементи, і ми отримаємо масив всередині масиву. Що, як ми не цього хотіли? Метод <code>concat</code> має поведінку, яка нам потрібна в цьому випадку, але він не додає елементи у існуючий масив, а створює та повертає новий масив. Але ми хотіли додати елементи у існуючий масив... Що ж робити? Писати цикл? Звісно, ні.</p>

<p>На допомогу приходить <code>apply</code>!</p>

<pre class="brush: js">var array = ['a', 'b'];
var elements = [0, 1, 2];
array.push.apply(array, elements);
console.info(array); // ["a", "b", 0, 1, 2]</pre>

<div class="note"></div>

<h3 id="Використання_apply_та_вбудовані_функції">Використання <code>apply</code> та вбудовані функції</h3>

<p>Розумне використання методу <code>apply</code> дозволяє використовувати вбудовані функції для деяких задач, які в іншому випадку ймовірно були б написані циклічним обходом значень масиву. Як приклад, ми збираємося використати <code>Math.max</code>/<code>Math.min,</code> щоб знайти максимальне/мінімальне значення масиву.</p>

<pre class="brush: js">// мінімальне/максимальне число в масиві
var numbers = [5, 6, 2, 3, 7];

// використання Math.min/Math.max з apply
var max = Math.max.apply(null, numbers);
// Це практично дорівнює Math.max(numbers[0], ...)
// або Math.max(5, 6, ...)

var min = Math.min.apply(null, numbers);

// в порівнянні з простим алгоритмом на основі цикла
max = -Infinity, min = +Infinity;

for (var i = 0; i &lt; numbers.length; i++) {
  if (numbers[i] &gt; max) {
    max = numbers[i];
  }
  if (numbers[i] &lt; min) {
    min = numbers[i];
  }
}
</pre>

<p>Але будьте обережні: використовуючи <code>apply</code> таким способом, ви ризикуєте перевищити ліміт кількості аргументів рушія JavaScript. Наслідки застосування функції, в якій забагато аргументів (більше, ніж десятки тисяч аргументів), різняться між різними рушіями (JavaScriptCore має жорстко закодований <a class="link-https" href="https://bugs.webkit.org/show_bug.cgi?id=80797">ліміт аргументів 65536</a>) тому, що ліміт (а насправді, навіть природа будь-якої поведінки надмірно великого стеку) є невизначеним. Деякі рушії викинуть виняток. Ще гірше, інші довільно обмежать кількість аргументів, які будуть насправді передані до застосованої функції. Для ілюстрації останнього випадку: якби такий рушій мав обмеження у чотири аргументи (справжні ліміти, звісно, значно більші), то замість цілого масиву у наведеному вище випадку до <code>apply</code> були б передані аргументи <code>5, 6, 2, 3</code></p>

<p>Якщо ваш масив значень може вирости до десятків тисяч значень, використовуйте гібридну стратегію: застосовуйте вашу функцію до фрагментів масиву, по одному за раз:</p>

<pre class="brush: js">function minOfArray(arr) {
  var min = Infinity;
  var QUANTUM = 32768;

  for (var i = 0, len = arr.length; i &lt; len; i += QUANTUM) {
    var submin = Math.min.apply(null,
                                arr.slice(i, Math.min(i+QUANTUM, len)));
    min = Math.min(submin, min);
  }

  return min;
}

var min = minOfArray([5, 6, 2, 3, 7]);

</pre>

<h3 id="Використання_методу_apply_для_ланцюгового_виконання_конструкторів">Використання методу <code>apply</code> для ланцюгового виконання конструкторів</h3>

<p>Ви можете використовувати <code>apply</code> для ланцюгового виконання {{jsxref("Operators/new", "конструкторів", "", 1)}} до об'єкта, подібно до Java. У наступному прикладі ми створимо глобальний метод {{jsxref("Function")}} під назвою <code>construct</code>, котрий дозволить використовувати подібний до масиву об'єкт з конструктором замість списку аргументів.</p>

<pre class="brush: js">Function.prototype.construct = function(aArgs) {
  var oNew = Object.create(this.prototype);
  this.apply(oNew, aArgs);
  return oNew;
};
</pre>

<div class="note">
<p><strong>Заувага:</strong> Метод <code>Object.create(),</code> що використовується вище, є відносно новим. В якості альтернативних методів, будь ласка, розгляньте наступні підходи:</p>

<p>Використання {{jsxref("Object/proto", "Object.__proto__")}}:</p>

<pre class="brush: js">Function.prototype.construct = function (aArgs) {
  var oNew = {};
  oNew.__proto__ = this.prototype;
  this.apply(oNew, aArgs);
  return oNew;
};</pre>

<p><a href="/uk/docs/Web/JavaScript/Closures">Замикання</a>:</p>

<pre class="brush: js">Function.prototype.construct = function(aArgs) {
  var fConstructor = this, fNewConstr = function() {
    fConstructor.apply(this, aArgs);
  };
  fNewConstr.prototype = fConstructor.prototype;
  return new fNewConstr();
};</pre>

<p>Конструктор {{jsxref("Function")}}:</p>

<pre class="brush: js">Function.prototype.construct = function (aArgs) {
  var fNewConstr = new Function("");
  fNewConstr.prototype = this.prototype;
  var oNew = new fNewConstr();
  this.apply(oNew, aArgs);
  return oNew;
};</pre>
</div>

<p>Приклад використання:</p>

<pre class="brush: js">function MyConstructor() {
  for (var nProp = 0; nProp &lt; arguments.length; nProp++) {
    this['property' + nProp] = arguments[nProp];
  }
}

var myArray = [4, 'Всім привіт!', false];
var myInstance = MyConstructor.construct(myArray);

console.log(myInstance.property1);                // виведе 'Всім привіт!'
console.log(myInstance instanceof MyConstructor); // виведе 'true'
console.log(myInstance.constructor);              // виведе 'MyConstructor'
</pre>

<div class="note">
<p><strong>Заувага:</strong> Цей не рідний метод <code>Function.construct</code> не буде працювати з деякими вбудованими конструкторами; такими, як {{jsxref("Date")}}, наприклад. У таких випадках, ви маєте використовувати метод {{jsxref("Function.prototype.bind")}} (наприклад, уявіть собі такий масив, що використовується з конструктором {{jsxref("Global_Objects/Date", "Date")}}: <code>[2012, 11, 4]</code>; у такому випадку вам доведеться написати щось по типу: <code>new (Function.prototype.bind.apply(Date, [null].concat([2012, 11, 4])))()</code>. Це не найкращий підхід, і, мабуть, не варто це робити у будь-якому виробничому середовищі).</p>
</div>

<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('ES3')}}</td>
   <td>{{Spec2('ES3')}}</td>
   <td>Початкове визначення. Реалізовано у JavaScript 1.3.</td>
  </tr>
  <tr>
   <td>{{SpecName('ES5.1', '#sec-15.3.4.3', 'Function.prototype.apply')}}</td>
   <td>{{Spec2('ES5.1')}}</td>
   <td></td>
  </tr>
  <tr>
   <td>{{SpecName('ES6', '#sec-function.prototype.apply', 'Function.prototype.apply')}}</td>
   <td>{{Spec2('ES6')}}</td>
   <td></td>
  </tr>
  <tr>
   <td>{{SpecName('ESDraft', '#sec-function.prototype.apply', 'Function.prototype.apply')}}</td>
   <td>{{Spec2('ESDraft')}}</td>
   <td></td>
  </tr>
 </tbody>
</table>

<h2 id="Сумісність_з_веб-переглядачами">Сумісність з веб-переглядачами</h2>

<div class="hidden">
<p>The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</p>
</div>

<p>{{Compat("javascript.builtins.Function.apply")}}</p>

<div id="compat-mobile"></div>

<h2 id="Див._також">Див. також</h2>

<ul>
 <li>Об'єкт {{jsxref("Functions/arguments", "arguments")}}</li>
 <li>{{jsxref("Function.prototype.bind()")}}</li>
 <li>{{jsxref("Function.prototype.call()")}}</li>
 <li>{{jsxref("Functions", "Функції та область видимості функції", "", 1)}}</li>
 <li>{{jsxref("Reflect.apply()")}}</li>
 <li><a href="/uk/docs/Web/JavaScript/Reference/Operators/Spread_syntax">Оператор розпакування</a></li>
</ul>