MDN’s new design is in Beta! A sneak peek: https://blog.mozilla.org/opendesign/mdns-new-design-beta/

Function.prototype.apply()

Переклад не закінчено. Будь ласка, допоможіть перекласти цю статтю з англійської.

Метод apply() викликає функцію з заданим значенням this і аргументами, які передані як масив (або масиво-подібний об'єкт).

Примітка: У той час, як синтаксис цієї функції є майже ідентичним до синтаксису call(), основною відмінністю є те, що метод call() приймає список аргументів, тоді як метод apply() приймає єдиний масив аргументів.

Синтаксис

fun.apply(thisArg, [argsArray])

Параметри

thisArg
Значення this, яке передане для виклику в функцію (fun). Зазначте, що this може не бути фактичним значенням, яке видиме методом: якщо даний метод є функцією в строгому режимі non-strict mode коду, null і undefined будуть замінені глобальними об'єктами, і значення-примітиви будуть складені.
argsArray
Масиво-подібний об'єкт, який визначає аргументи, з якими функція (fun) має бути викликана, або null або undefined якщо жодних аргументів не було передано в дану функцію. Починаючи з ECMAScript 5 ці аргументи можуть бути загальними масиво-подібними замість масиву. Дивіться нижче інформацію по browser compatibility.

Значення, яке повертається

Результат виконання даної функції з зазначеним значенням this і аргументами.

Опис

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

Метод apply дуже подібний до call(), за виключенням типу аргументів, які він підтримує. Ви можете використовувати масив аргументів замість іменованого набору параметрів. З методом apply, ви можете використовувати літерал масиву, для прикладу, fun.apply(this, ['eat', 'bananas']), або об'єкт Array, для прикладу, fun.apply(this, new Array('eat', 'bananas')).

Ви також можете використовувати arguments для параметру argsArray. Аргументами є локальні змінні функції. Вони можуть бути використані для всіх не зазначених аргументів об'єкта, який викликається. Хоча, вам не потрібно знати аргументи об'єкта, який викликається коли ви використовуєте метод apply. Ви можете використовувати arguments, щоб передавати всі аргументи в викликаний об'єкт. Викликаний об'єкт тоді відповідає за обробку аргументів.

З того часу, коли вийшов ECMAScript 5-й ви можете також використовувати будь-який вид об'єктів які є масиво-подібними, так що на практиці це означає мати поле length і цілі параметри в діапазоні (0...length-1). Як приклад, ви можете викоритовувати NodeList або власноруч написаний об'єкт виду { 'length': 2, '0': 'eat', '1': 'bananas' }.

Більшість браузерів, включаючи Chrome 14 і Internet Explorer 9, досі не приймають масиво-подібні об'єкти і будуть кидати помилку.

Приклади

Використання методу apply для ланцюгового виконання конструкторів

Ви можете використовувати apply для ланцюгового виконання constructors до об'єкта, подібно до Java. В наступному прикладі ми створимо глобальний метод Function і назвемо construct, котрий дозволить вам використовувати масиво-подібний об'єкт з конструктором замість списку аргументів.

Function.prototype.construct = function(aArgs) {
  var oNew = Object.create(this.prototype);
  this.apply(oNew, aArgs);
  return oNew;
};

Примітка: Метод Object.create(), який використовувався вище є відносно новим. Як альтернативу, викоритовуйте замикання, будь ласка, розгляньте наступну альтернативу:

Function.prototype.construct = function(aArgs) {
  var fConstructor = this, fNewConstr = function() { 
    fConstructor.apply(this, aArgs); 
  };
  fNewConstr.prototype = fConstructor.prototype;
  return new fNewConstr();
};

Приклад використання:

function MyConstructor() {
  for (var nProp = 0; nProp < arguments.length; nProp++) {
    this['property' + nProp] = arguments[nProp];
  }
}

var myArray = [4, 'Hello world!', false];
var myInstance = MyConstructor.construct(myArray);

console.log(myInstance.property1);                // виведе 'Hello world!'
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])))() — у всякому разі це не найкращий спосіб робити так і ймовірно не варто викоритовувати це у виробничому середовищі).

Використання методу 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) тому, що даний ліміт (indeed even the nature of any excessively-large-stack behavior) є невизначеним. Деякі середовища будуть кидати помилку. More perniciously, others will arbitrarily limit the number of arguments actually passed to the applied function. (To illustrate this latter case: if such an engine had a limit of four arguments [actual limits are of course significantly higher], it would be as if the arguments 5, 6, 2, 3 had been passed to apply in the examples above, rather than the full array.) Якщо ваш масив значень може вирости до десятків тисяч, використовуйте гібридну стратегію: застосовуйте вашу функцію до шматків масиву:

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 в "мавпячому-латанні" ("monkey-patching")

Метод apply може бути найкращим способом для мавпячого-латання (monkey-patch) вбудованих функцій Firefox, або JS бібліотек. Задана функція someobject.foo, ви можете змінити дану функцію трохи хакерським способом, ось так:

var originalfoo = someobject.foo;
someobject.foo = function() {
  // Do stuff before calling function
  console.log(arguments);
  // Call the function as it would have been called normally:
  originalfoo.apply(this, arguments);
  // Run stuff after, here.
}

Цей метод особливо зручний коли ви хочете відлагоджувати події, або взаємодіяти з чимось, що не має API на подобі різноманітних .on([event]... подій таких, які можна використовувати в інспекторі інструментів розробника).

Специфікації

Специфікація Статус Коментар
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 Latest Draft (ECMA-262)
The definition of 'Function.prototype.apply' in that specification.
Draft  

Сумісність із браузерами

Особливість Chrome Firefox (Gecko) Internet Explorer Opera Safari
Базова підтримка (Yes) (Yes) (Yes) (Yes) (Yes)
ES 5.1 generic array-like object as arguments (Yes) 4.0 (2.0) ? ? ?
Особливість Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Базова підтримка (Yes) (Yes) (Yes) (Yes) (Yes) (Yes)
ES 5.1 generic array-like object as arguments ? ? 4.0 (2.0) ? ? ?

Дивитися також

Мітки документа й учасники

 Зробили внесок у цю сторінку: Wsewlad, piton13
 Востаннє оновлена: Wsewlad,