Questa traduzione è incompleta. Collabora alla traduzione di questo articolo dall’originale in lingua inglese.
Il metodo apply()
chiama una funzione passandole il "this
" ed i parametri forniti sottoforma di array (o array-like object).
Nota: Mentre la sintassi di questa funzione è quasi completamente identica a quella di call()
, la fondamentale differenza è che call()
accetta una lista di parametri, mentre apply()
accetta un singolo array contenente una lista di parametri.
Sintassi
fun.apply(thisArg, [argsArray])
Parametri
thisArg
- Il valore del
this
da fornire alla chiama afun
. Nota che questo potrebbe non essere l'effettivo valore visto dal metodo: se il metodo non è eseguito in strict mode,null
edundefined
saranno rimpiazzati dall'oggetto globale. argsArray
- Un array-like object che specifica i parametri con la quale la funzione
fun
deve essere chiamata. Può essere anchenull
oundefined
nel caso nessun parametro dovesse essere passato. A partire da ECMAScript 5 questi parametri possono essere un qualunque array-like object invece di un semplice array. Vedi sotto per le compatibilità nei browser.
Descrizione
this
solitamente si riferisce all'oggetto corrente, ma grazie ad apply
è possibile scrivere un metodo una sola volta e riusarlo più volte su oggetti differenti passando ad apply, appunto, un this differente. Cosi viene eliminata la necessità di riscrivere di nuovo lo stesso metodo per un oggetto diverso.
apply
è molto simile a call()
, eccezion fatta per il modo in cui i parametri vengono passati. Puoi utilizzare un array di parametri invece della solita lista. Con apply
, ad esempio, puoi utilizzare il seguente array literal: fun.apply(this, ['eat', 'bananas'])
, o il seguente oggetto Array
: fun.apply(this, new Array('eat', 'bananas'))
.
Puoi anche utilizzare arguments
per il parametro argsArray.
arguments
è una variabile locale di tutte le funzioni. Può essere utilizzata per tutti i parametri non specificati dell'oggetto chiamato. In più, non è necessario che si conoscano i parametri dell'oggetto chiamato quando si utilizza apply.
Da ECMAScript 5 puoi anche usare qualunque tipo di array-like object. Ad esempio puoi utilizzare un NodeList
o un oggetto come { 'length': 2, '0': 'eat', '1': 'bananas' }
.
Esempi
Utilizzare apply per concatenare costruttori
Puoi utilizzare apply per concatenare costruttori per un oggetto, in maniera simile a Java. Nel seguente esempio creeremo una Function
globale chiamata construct
, che ti permetterà di utilizzare un array-like object con un costruttore anziché una lista di argomenti.
Function.prototype.construct = function (aArgs) { var oNew = Object.create(this.prototype); this.apply(oNew, aArgs); return oNew; };
Note: Il metodo Object.create()
usato nell'esempio sovrastante è relativamente nuovo. Per un alternativa che utilizza le closures considera questo pezzo di codice:
Function.prototype.construct = function(aArgs) { var fConstructor = this, fNewConstr = function() { fConstructor.apply(this, aArgs); }; fNewConstr.prototype = fConstructor.prototype; return new fNewConstr(); };
Esempio d'uso:
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); // logs 'Hello world!' console.log(myInstance instanceof MyConstructor); // logs 'true' console.log(myInstance.constructor); // logs 'MyConstructor'
Note: Il metodo non nativo Function.construct
non funzionerà con alcuni costruttori nativi (come Date
). In questi casi devi usare Function.prototype.bind
. Immagina ad esempio di avere un array come il seguente da utilizzare con il costruttore Date
: [2012, 11, 4]
; In questo caso dovresti scrivere qualcosa come: new (Function.prototype.bind.apply(Date, [null].concat([2012, 11, 4])))()
— ad ogni modo questo non è il miglior modo di fare le cose e non andrebbe mai usato in produzione.
Utilizzare apply combinato alle funzioni built-in
Un intelligente uso di apply
ti permette di utilizzare delle funzioni built-in per dei compiti che altrimenti sarebbero stati fatti, nel caso sottostante, ciclando l'array e scorrendo ogni suo elemento e sottoponendolo a dei controlli. L'esempio seguente dimostra come trovare il massimo / minimo valore all'interno di un array utilizzando Math.max
/Math.min
.
// min/max number in an array var numbers = [5, 6, 2, 3, 7]; // using Math.min/Math.max apply var max = Math.max.apply(null, numbers); // This about equal to Math.max(numbers[0], ...) // or Math.max(5, 6, ...) var min = Math.min.apply(null, numbers); // vs. simple loop based algorithm 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]; } }
Ma tieni a mente che nell'usare apply in questo modo si corre il rischio di superare il limite imposto dal motore JavaScript degli argomenti che possono essere passati ad una funzione.
Le conseguenze nel fare ciò variano da motore a motore (ad esempio JavaScriptCore ha il limite settato a mano di 65536 parametri), perché il limite non è specificato. Alcuni motori lanceranno una eccezione. Altri invece limiteranno arbitrariamente il numero dei parametri passati alla funzione su cui viene usato il metodo apply().
(Un esempio di quest'ultimo caso potrebbe essere quello di un motore che ha questo limite settato a 4 e, nell'esempio sovrastante, gli unici parametri che effettivamente saranno passati alla funzione saranno 5, 6, 2, 3
, piuttosto che l'intero array.) Una decisione saggia, nel caso si prevede la possibilità di raggiungere un enorme numero di parametri, sarebbe quella di parzializzare il numero di parametri per lotti:
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]);
Usare apply come "monkey-patch"
L'attività del "monkey-patching" consiste nel modificare il funzionamento di un metodo senza dover andare a mettere mano al codice sorgente (cosa da evitare sempre e comunque). Difatti Apply può rivelarsi il modo migliore di modificare il funzionamento, ad esempio, di una funzione interna a Firefox o di una qualunque altra libreria JS. Data una funzione someobject.foo
, è possibile modificarne il funzionamento in questo modo:
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. }
Questo metodo ritorna particolarmente utile quando vuoi debuggare eventi e interfacce con qualcosa che non espone API come i diversi eventi .on([event]...
(usabili anche dal Devtools Inspector).
Specifiche
Specifica | Stato | Commento |
---|---|---|
ECMAScript 3rd Edition (ECMA-262) | Standard | Definizione iniziale. Implementato in 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 2017 Draft (ECMA-262) The definition of 'Function.prototype.apply' in that specification. |
Draft |
Compatibilità Browser
Feature | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|
Supporto base | (Yes) | (Yes) | (Yes) | (Yes) | (Yes) |
ES 5.1 generico array-like object come arguments |
? | 4.0 (2.0) | ? | ? | ? |
Feature | Android | Chrome for Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
---|---|---|---|---|---|---|
Supporto base | (Yes) | (Yes) | (Yes) | (Yes) | (Yes) | (Yes) |
ES 5.1 generico array-like object come arguments |
? | ? | 4.0 (2.0) | ? | ? | ? |