2009-11-22 3 views
23

me encontré con el siguiente código:Una pregunta sobre la rebanada de empalme y métodos de JavaScript

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

    // some more code 
}; 

Básicamente, el resultado en args es una matriz que es una copia de la arguments sin su primer elemento.

Pero lo que no puedo entender exactamente es la razón por f 's arguments (que es un objeto que contiene los argumentos introducidos de la función en un objeto de matriz similar) objeto se pasa al método slice y cómo slice(1) es la eliminación de la primer elemento (ubicado en el índice 0).

¿Alguien puede explicarlo por mí?

P.S. El código es de esta partial application function

Respuesta

40

< Nota>
el código real de que linked answer es:

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

es decir "corte", no "empalme"
</Nota>

En primer lugar, el método slice se utiliza a menudo para 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'] 

Así que la respuesta corta es que el código es, básicamente, emulando:

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

Sin embargo, no puede hacerlo directamente. El special arguments object (disponible dentro del contexto de ejecución de todas las funciones de JavaScript), aunque Array-como en que admite la indexación a través del operador [] con teclas numéricas, no es realmente una matriz; No se puede .push en él, .pop fuera de él, o que .slice, etc.

La forma en que el código logra esto es por "engañar" a la función slice (que de nuevo no está disponible en el objeto arguments) para ejecutar en el contexto dearguments, a través de 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) logra la misma cosa, pero hace una llamada ajena a splice(1), que elimina elementos de la array devuelto desde Array.prototype.slice.call(arguments) comenzando en el índice 1 y continuando hasta el final de la matriz. splice(1) no funciona en IE (técnicamente falta un segundo parámetro que indica cuántos elementos eliminar que IE y ECMAScript requieren).

+0

Lo siento por la diferencia de código, pero he copiado el código que había pegado aquí http://stackoverflow.com/questions/373157/how- can-i-pass-a-reference-to-a-function-with-parameters de la respuesta a la que me he vinculado en esta pregunta, pero el autor cambió el script mientras tanto. Una vez más, perdón por eso –

+0

@Andreas: check mah updatez –

+0

¡Gran respuesta! +1 –

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

primera tiene una copia de arguments (*), a continuación, elimina todo menos el primer elemento de ella (de un modo no estándar), y asigna esos artículos se eliminen a args.

La matriz adicional que se produce, luego se altera y se descarta es bastante redundante.Sería mejor decir - como la versión de la respuesta se ha vinculado a hecho lo hace:

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

aplicación de función parcial es también una característica del método function.bind, siendo normalizado por el ECMAScript Quinta edición. Hasta que los navegadores lo hayan implementado, puede elegir una versión alternativa de JS desde la parte inferior de this answer.

*: array.slice() es la expresión normal para copiar una matriz, y array.slice(1) para tomar la cola. Tiene que llamarse explícitamente a través del Array.prototype porque arguments no es una matriz, aunque se parece a una, por lo que no tiene los métodos de matriz normales. Este es otro de los errores extraños de JavaScript.

Muy a menudo se ven personas que usan los métodos Array.prototype en objetos que no son matrices; el estándar ECMAScript Third Edition se sale de su camino para decir que esto está bien para arguments como una matriz, pero no que también puede hacerlo en otros array-likes que pueden ser objetos host, como NodeList o HTMLCollection . Aunque es posible que se salga con la suya llamando a los métodos Array.prototype en una matriz que no es de matriz en muchos navegadores hoy en día, el único lugar seguro es hacerlo en arguments.

+0

ES5 ahora documenta explícitamente muchos de los métodos Array.prototype para trabajar en * cualquier objeto * tipo array, por lo que debería ser seguro confiar en que continuará trabajando. – natevw

0

El valor devuelto de un empalme es una matriz de los elementos que se eliminaron, pero el conjunto original (o el objeto similar a una matriz) se trunca en el índice de empalme.

Hacer una copia con slice conserva la matriz original de argumentos, supuestamente para usar más adelante en la función.

En este caso, el mismo resultado se puede tener 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 
Cuestiones relacionadas