Skip to content

Latest commit

 

History

History
123 lines (88 loc) · 4.13 KB

File metadata and controls

123 lines (88 loc) · 4.13 KB

L'oggetto arguments

Ogni scope di funzione in JavaScript può accedere alla speciale variabile arguments. Questa variabile mantiene un elenco di tutti gli argomenti che sono stati passati alla funzione.

Nota: nel caso arguments sia stato già definito nello scope della funzione tramite una dichiarazione var o come parametro formale, l'oggetto arguments non sarà creato.

L'oggetto arguments non è un Array. Sebbene abbia in parte la semantica di un array (nello specifico la proprietà length), esso non eredita da Array.prototype ed è a tutti gli effetti un Object.

Proprio per questo motivo, non è possibile usare su arguments i metodi standard degli array come push, pop, slice. E mentre l'iterazione con un semplice ciclo for funzionerà senza problemi, sarà necessario convertire l'oggetto in un vero Array per poter usare i metodi standard di Array con esso.

Conversione ad array

Il codice seguente ritornerà un nuovo Array contenenente tutti gli elementi dell'oggetto arguments.

Array.prototype.slice.call(arguments);

Dato che questa conversione è lenta, non è raccomandato usarla in sezioni di codice in cui la performance è un fattore critico.

Passaggio di argomenti

Quello che segue è il metodo raccomandato per passare argomenti da una funzione ad un'altra.

function foo() {
    bar.apply(null, arguments);
}
function bar(a, b, c) {
    // codice da eseguire
}

Un altro trucco è quello di usare call e apply insieme per creare veloci contenitori senza vincoli.

function Foo() {}

Foo.prototype.method = function(a, b, c) {
    console.log(this, a, b, c);
};

// Crea una versione senza vincoli di "method"
// Richiede i parametri: this, arg1, arg2...argN
Foo.method = function() {

    // Risultato: Foo.prototype.method.call(this, arg1, arg2... argN)
    Function.call.apply(Foo.prototype.method, arguments);
};

Parametri formali e indici degli argomenti

L'oggetto arguments crea funzioni getter e setter sia per le sue proprietà che per i parametri formali della funzione.

Come risultato, la modifica del valore di un parametro formale modificherà anche il valore della corrispondente proprietà nell'oggetto arguments, e vice versa.

function foo(a, b, c) {
    arguments[0] = 2;
    a; // 2

    b = 4;
    arguments[1]; // 4

    var d = c;
    d = 9;
    c; // 3
}
foo(1, 2, 3);

Miti e verità sulla performance

Il solo caso in cui l'oggetto arguments non viene creato, è quando esso viene dichiarato come un nome all'interno di una funzione o uno dei suoi parametri formali. Non importa che venga usato o meno.

Sia i getter che i setter vengono sempre creati. Perciò, il loro utilizzo non ha praticamente alcun impatto sulle prestazioni, specialmente nel mondo reale dove nel codice c'è più di un semplice accesso alle proprietà dell'oggetto arguments.

ES5 Nota: questi getter e setter non vengono creati in strict mode.

Ad ogni modo, c'è un caso che ridurrà drasticamente la performance nei motori JavaScript moderni. È il caso dell'utilizzo di arguments.callee.

function foo() {
    arguments.callee; // fa qualcosa con questo oggetto funzione
    arguments.callee.caller; // e l'oggetto funzione chiamante
}

function bigLoop() {
    for(var i = 0; i < 100000; i++) {
        foo(); // normalmente sarebbe sostituito con il suo codice...
    }
}

Nel codice qui sopra, foo non può più essere soggetto ad inlining dal momento che necessita di conoscere sia se stesso che il suo chiamante. Questo non solo annulla possibili guadagni prestazionali ottenibili con l'inlining, ma spezza anche il principio di incapsulazione perché la funzione ora potrebbe essere dipendente da uno specifico contesto di esecuzione.

L'utilizzo di arguments.callee o di qualsiasi altra delle sue proprietà è altamente sconsigliato.

ES5 Nota: In strict mode, arguments.callee lancierà un TypeError dato che il suo utilizzo è stato deprecato.