2009-11-22 7 views
23

mi sono imbattuto nel seguente codice:Una domanda sulla fetta e di splicing metodi di JavaScript

var f = function() { 
    var args = Array.prototype.slice.call(arguments).splice(1); 

    // some more code 
}; 

In sostanza, il risultato in args è una matrice che è una copia del arguments senza il suo primo elemento.

Ma quello che non riesco a capire esattamente è il motivo per f s' arguments (che è un oggetto che contiene gli argomenti immessi della funzione in un oggetto array-like) oggetto viene passato al metodo slice e come slice(1) sta rimuovendo la primo elemento (posizionato all'indice 0).

Qualcuno può spiegarlo per favore?

P.S. Il codice è da questo partial application function

risposta

40

< Nota>
il codice effettivo da quello linked answer è:

var args = Array.prototype.slice.call(arguments, 1); 

cioè "slice", non "splice"
</Note>

Innanzitutto, il metodo slice viene spesso utilizzato per make a copy of the array it's called on:

var a = ['a', 'b', 'c']; 
var b = a.slice(); // b is now a copy of a 
var c = a.slice(1); // c is now ['b', 'c'] 

Quindi la risposta breve è che il codice è fondamentalmente emulando:

arguments.slice(1); // discard 1st argument, gimme the rest 

Tuttavia non è possibile farlo direttamente. special arguments object (disponibile all'interno del contesto di esecuzione di tutte le funzioni JavaScript), sebbene l'Array- come in quanto supporta l'indicizzazione tramite l'operatore [] con tasti numerici, non sia in realtà una matrice; Non è possibile .push su di esso, .pop fuori di esso, o .slice esso, ecc

Il modo in cui il codice esegue questo è di "ingannando" la funzione slice (che a sua volta non è disponibile nell'oggetto arguments) per eseguire nel contesto diarguments, via Function.prototype.call:

Array.prototype.slice // get a reference to the slice method 
         // available on all Arrays, then... 
    .call(    // call it, ... 
    arguments,  // making "this" point to arguments inside slice, and... 
    1     // pass 1 to slice as the first argument 
) 

Array.prototype.slice.call(arguments).splice(1) compie la stessa cosa, ma effettua una chiamata estraneo alla splice(1), che rimuove elementi dal array restituito da Array.prototype.slice.call(arguments) a partire dall'indice 1 e proseguendo fino alla fine dell'array. splice(1) non funziona in IE (tecnicamente manca un secondo parametro che indica quanti elementi rimuovere che IE ed ECMAScript richiedono).

+0

Ci scusiamo per la differenza di codice, ma ho copiato il codice che avevo qui incollato http://stackoverflow.com/questions/373157/how- can-i-pass-a-reference-to-a-function-with-parameters dalla risposta a cui ho fatto riferimento in questa domanda, ma l'autore ha cambiato lo script nel frattempo. Ancora una volta, mi dispiace per quello –

+0

@Andreas: controlla mah updatez –

+0

Ottima risposta! +1 –

3
var args = Array.prototype.slice.call(arguments).splice(1); 

Prima prende una copia di arguments (*), quindi rimuove tutti, ma il primo elemento da esso (in modo non-standard), e assegna gli elementi essere rimossi a args.

L'array extra prodotto, quindi modificato e gettato via è abbastanza ridondante.Sarebbe meglio dire - come la versione nella risposta si è collegato al anzi fa:

var args = Array.prototype.slice.call(arguments, 1); 

applicazione funzione parziale è anche una caratteristica del metodo function.bind, essendo standardizzato da ECMAScript quinta edizione. Fino a quando i browser non l'hanno implementato, puoi prendere una versione nativa di JS di fallback dal fondo di this answer.

*: array.slice() è il normale idioma per copiare un array e array.slice(1) per prendere la coda. È stato chiamato esplicitamente tramite Array.prototype perché arguments non è un array, anche se sembra proprio come uno, quindi non ha i normali metodi di array. Questo è un altro degli strani errori di JavaScript.

Spesso si vedono persone che usano i metodi Array.prototype su oggetti che non sono Matrici; lo standard ECMAScript Third Edition fa di tutto per dire che questo è OK per il tipo di array arguments, ma non che si può fare anche su altri array-like che potrebbero essere oggetti host, come NodeList o HTMLCollection . Sebbene tu possa scappare chiamando i metodi Array.prototype su un non-Array in molti browser oggi, l'unico posto in cui è effettivamente sicuro farlo è il arguments.

+0

ES5 ora documenta esplicitamente molti dei metodi Array.prototype per lavorare su * qualsiasi * oggetto tipo array, quindi dovrebbe essere sicuro affidarsi a quello continuare a lavorare. – natevw

0

Il valore restituito di una giuntura è una matrice degli elementi che sono stati rimossi, ma l'array originale (o l'oggetto di tipo array), viene troncato nell'indice di splicing.

Effettuare una copia con slice mantiene l'array di argomenti originale, presumibilmente per l'utilizzo più avanti nella funzione.

In questo caso lo stesso risultato si può avere con args = [].slice.call(arguments, 1)

function handleArguments(){ 
var A= [].slice.call(arguments).splice(1); 
//arguments is unchanged 
var s= 'A='+A+'\narguments.length='+arguments.length; 

var B= [].splice.call(arguments, 1); 
// arguments now contains only the first parameter 
s+= '\n\nB='+B+'\narguments.length='+arguments.length; 
return s; 
} 

// test 
alert(handleArguments(1, 2, 3, 4)); 

returned value: 
//var A= [].slice.call(arguments).splice(1); 
A=2,3,4 
arguments.length=4 

//var B= [].splice.call(arguments, 1); 
B=2,3,4 
arguments.length=1