Метод apply()
викликає функцію із заданим значенням this
та аргументами, переданими у вигляді масиву (або подібного до масиву об'єкта).
Заувага: Хоча синтаксис цієї функції є майже ідентичним до синтаксису call()
, фундаментальна відмінність полягає в тому, що метод call()
приймає список аргументів, тоді як метод apply()
приймає єдиний масив аргументів.
Заувага: Коли першим аргументом є undefined або null, схожий результат можна отримати за допомогою оператора розпакування масивів.
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 https://github.com/mdn/interactive-examples and send us a pull request.
Синтаксис
function.apply(thisArg, [argsArray])
Параметри
thisArg
- Значення
this
, передане для виклику у функціюfunction
. Зазначте, щоthis
може не бути фактичним значенням, яке бачить метод: якщо метод є функцією не у строгому режимі,null
таundefined
будуть замінені глобальним об'єктом, а прості значення будуть запаковані. Цей аргумент є обов'язковим. argsArray
- Необов'язковий. Подібний до масиву об'єкт, що визначає аргументи, з якими функція має бути викликана, або
null
чиundefined
, якщо жодних аргументів не має бути передано у функцію. Починаючи з ECMAScript 5, ці аргументи можуть бути загальними подібними до масиву об'єктами замість масиву. Дивіться нижче інформацію щодо сумісності з веб-переглядачами.
Значення, яке повертається
Результат виконання функції з вказаним значенням this
та аргументами.
Опис
Ви можете присвоїти інший об'єкт this
, коли викликаєте існуючу функцію. this
посилається на поточний об'єкт, з якого здійснюється виклик. З apply
ви можете написати метод один раз, а потім успадковувати його в іншому об'єкті, без необхідності переписувати метод для нового об'єкта.
Метод apply
дуже схожий на call()
, за виключенням типу аргументів, які він підтримує. Ви використовуєте масив аргументів замість списку аргументів (параметрів). З методом apply
ви також можете використовувати літерал масиву, для прикладу, func.apply(this, ['їсти', 'банани'])
, або об'єкт Array
, для прикладу, func.apply(this, new Array('їсти', 'банани'))
.
Ви також можете використати об'єкт arguments
як параметр argsArray
. arguments
- локальна змінна функції. Вона може використовуватись для всіх не заданих аргументів об'єкта, який викликається. Таким чином, вам не потрібно знати аргументи об'єкта, що викликається, коли ви використовуєте метод apply
. Ви можете скористатись об'єктом arguments,
щоб передати усі аргументи. Далі об'єкт, який викликається, відповідає за обробку аргументів.
З появою 5-ї версії ECMAScript, ви також можете використовувати будь-який подібний до масиву об'єкт, отже, на практиці це означає, що він має поле length
та цілі числа в якості параметрів у діапазоні (0...length-1)
. Як приклад, ви тепер можете використати NodeList
або власноруч написаний об'єкт виду { 'length': 2, '0': 'їсти', '1': 'банани' }
.
Чимало більш старих переглядачів, в тому числі Chrome <17 та Internet Explorer <9, не приймають подібні до масиву об'єкти і викидатимуть виняток.
Приклади
Використання apply
для додавання масиву до іншого масиву
Ми можемо використати метод push
, щоб додати елемент до масиву. І, оскільки push
приймає змінну кількість аргументів, ми також можемо додати кілька елементів за раз. Але, якщо ми передамо у push
масив, він додасть, власне, масив єдиним елементом, замість того, щоб додати окремі елементи, і ми отримаємо масив всередині масиву. Що, як ми не цього хотіли? Метод concat
має поведінку, яка нам потрібна в цьому випадку, але він не додає елементи у існуючий масив, а створює та повертає новий масив. Але ми хотіли додати елементи у існуючий масив... Що ж робити? Писати цикл? Звісно, ні.
На допомогу приходить apply
!
var array = ['a', 'b'];
var elements = [0, 1, 2];
array.push.apply(array, elements);
console.info(array); // ["a", "b", 0, 1, 2]
Використання apply
та вбудовані функції
Розумне використання методу apply
дозволяє використовувати вбудовані функції для деяких задач, які в іншому випадку ймовірно були б написані циклічним обходом значень масиву. Як приклад, ми збираємося використати Math.max
/Math.min,
щоб знайти максимальне/мінімальне значення масиву.
// мінімальне/максимальне число в масиві
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 < numbers.length; i++) {
if (numbers[i] > max) {
max = numbers[i];
}
if (numbers[i] < min) {
min = numbers[i];
}
}
Але будьте обережні: використовуючи apply
таким способом, ви ризикуєте перевищити ліміт кількості аргументів рушія JavaScript. Наслідки застосування функції, в якій забагато аргументів (більше, ніж десятки тисяч аргументів), різняться між різними рушіями (JavaScriptCore має жорстко закодований ліміт аргументів 65536) тому, що ліміт (а насправді, навіть природа будь-якої поведінки надмірно великого стеку) є невизначеним. Деякі рушії викинуть виняток. Ще гірше, інші довільно обмежать кількість аргументів, які будуть насправді передані до застосованої функції. Для ілюстрації останнього випадку: якби такий рушій мав обмеження у чотири аргументи (справжні ліміти, звісно, значно більші), то замість цілого масиву у наведеному вище випадку до apply
були б передані аргументи 5, 6, 2, 3
.
Якщо ваш масив значень може вирости до десятків тисяч значень, використовуйте гібридну стратегію: застосовуйте вашу функцію до фрагментів масиву, по одному за раз:
function minOfArray(arr) {
var min = Infinity;
var QUANTUM = 32768;
for (var i = 0, len = arr.length; i < 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]);
Використання методу apply
для ланцюгового виконання конструкторів
Ви можете використовувати apply
для ланцюгового виконання конструкторів до об'єкта, подібно до Java. У наступному прикладі ми створимо глобальний метод Function
під назвою construct
, котрий дозволить використовувати подібний до масиву об'єкт з конструктором замість списку аргументів.
Function.prototype.construct = function(aArgs) {
var oNew = Object.create(this.prototype);
this.apply(oNew, aArgs);
return oNew;
};
Заувага: Метод Object.create(),
що використовується вище, є відносно новим. В якості альтернативних методів, будь ласка, розгляньте наступні підходи:
Використання Object.__proto__
:
Function.prototype.construct = function (aArgs) {
var oNew = {};
oNew.__proto__ = this.prototype;
this.apply(oNew, aArgs);
return oNew;
};
Function.prototype.construct = function(aArgs) {
var fConstructor = this, fNewConstr = function() {
fConstructor.apply(this, aArgs);
};
fNewConstr.prototype = fConstructor.prototype;
return new fNewConstr();
};
Конструктор Function
:
Function.prototype.construct = function (aArgs) {
var fNewConstr = new Function("");
fNewConstr.prototype = this.prototype;
var oNew = new fNewConstr();
this.apply(oNew, aArgs);
return oNew;
};
Приклад використання:
function MyConstructor() {
for (var nProp = 0; nProp < 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'
Заувага: Цей не рідний метод Function.construct
не буде працювати з деякими вбудованими конструкторами; такими, як Date
, наприклад. У таких випадках, ви маєте використовувати метод Function.prototype.bind
(наприклад, уявіть собі такий масив, що використовується з конструктором Date
: [2012, 11, 4]
; у такому випадку вам доведеться написати щось по типу: new (Function.prototype.bind.apply(Date, [null].concat([2012, 11, 4])))()
. Це не найкращий підхід, і, мабуть, не варто це робити у будь-якому виробничому середовищі).
Специфікації
Специфікація | Статус | Коментар |
---|---|---|
ECMAScript 3rd Edition (ECMA-262) | Standard | Початкове визначення. Реалізовано у JavaScript 1.3. |
ECMAScript 5.1 (ECMA-262) The definition of 'Function.prototype.apply' in that specification. |
Standard | |
ECMAScript 2015 (6th Edition, ECMA-262) The definition of 'Function.prototype.apply' in that specification. |
Standard | |
ECMAScript (ECMA-262) The definition of 'Function.prototype.apply' in that specification. |
Living Standard |
Сумісність з веб-переглядачами
BCD tables only load in the browser