2008-09-23 8 views
27

Estoy revisando el excelente Advanced javascript tutorial de John Resig y no entiendo completamente cuál es la diferencia entre las siguientes llamadas: (tenga en cuenta que 'arguments' es una palabra javascript incorporada y no es exactamente una gran variedad de ahí la piratería con el Array.slice en lugar de simplemente llamando arguments.slice)Diferencia entre Array.slice y Array(). Slice

>>> arguments 
[3, 1, 2, 3] 
>>> Array.slice.call(arguments) 
3,1,2,3 0=3 1=1 2=2 3=3 
>>> Array.slice.call(arguments, 1) 
[] 
>>> Array().slice.call(arguments) 
3,1,2,3 0=3 1=1 2=2 3=3 
>>> Array().slice.call(arguments, 1) 
1,2,3 0=1 1=2 2=3 

Básicamente mi malentendido se reduce a la diferencia entre Array.slice y array(). rebanada. ¿Cuál es exactamente la diferencia entre estos dos y por qué Array.slice.call no se comporta como se esperaba? (que devuelve todos menos el primer elemento de la lista de argumentos).

Respuesta

38

No del todo.

Mira lo que sucede cuando se llama String.substring.call ("foo", 1) y la cadena() substring.call ("foo", 2):.

>>> String.substring.call("foo", 1) 
"1" 

>>> String().substring.call("foo", 1) 
"oo" 

Array.slice es tampoco haciendo referencia de forma adecuada a la función de división asociada al prototipo de matriz ni a la función de división asociada a ninguna instancia de matriz instanciada (como Array() o []).

El hecho de que Array.slice sea incluso no nulo en absoluto es una implementación incorrecta del objeto (/ función/constructor). Intente ejecutar el código equivalente en IE y obtendrá un error que Array.slice es nulo.

Es por eso que Array.slice no se comporta correctamente (ni lo hace String.substring).

prueba (el siguiente es algo que nunca se debe esperar basado en la definición de la rebanada() ... como subcadena() anterior):

>>> Array.slice.call([1,2], [3,4]) 
3,4 

Ahora, si se llama adecuadamente rebanada() en ya sea un objeto instanciado o el prototipo de matriz, que obtendrá lo que se espera:

>>> Array.prototype.slice.call([4,5], 1) 
[5] 
>>> Array().slice.call([4,5], 1) 
[5] 

Más pruebas ...

>>> Array.prototype.slice == Array().slice 
true 
>>> Array.slice == Array().slice 
false 
+0

No sé cómo se comportó de navegadores '08, pero a principios de 2013, 'String.substring.call' lanza una TypeError en Chrome (ya que el constructor de' string' no tiene una propiedad 'substring') . – bfavaretto

+0

@bfavaretto, Firefox (solo) implementa 'Array.slice' y' String.substring'. El asker sin duda estaba usando Firefox cuando estaba probando esto. –

+0

Gracias por la información, @NathanWall. Eso es bastante extraño de Firefox, probablemente algo que agregaron como atajo a 'String.prototype.substring' et al. por compatibilidad con versiones anteriores ... y aparentemente se ha mantenido por un tiempo. – bfavaretto

6

La matriz es solo una función, aunque especial (utilizada para inicializar matrices). Array.slice es una referencia a la función slice() en el prototipo Array. Solo se puede invocar en un objeto de matriz y no en el Constructor (es decir, la matriz). Sin embargo, Array parece comportarse especialmente, ya que Array() devuelve una matriz vacía. Esto no parece funcionar para las funciones de Constructor no integradas (allí tienes que usar nuevas). Así

Array().slice.call 

es lo mismo que

[].slice.call 
-1

Supongo que Array es un prototipo, mientras que Array() es un objeto de matriz real. Dependiendo de la interpretación de JavaScript, puede ser que invoque directamente el método prototipo de un tipo de objeto incorporado o no. No creo que la especificación diga que tiene que funcionar, solo que llamarlo a un objeto instanciado funciona.

0

creo matriz es el tipo y Array() es la función constructora.

Jugando en FireBug:

>>> Array === Array() 
false 

>>> Array.constructor 
Function() 

>>> Array().constructor 
Array() 
1

Cómo es cualquier llamada a slice.call() que trabajan en los ejemplos proporcionados desde un parámetro de contexto no está siendo suministrado? ¿El sector implementa su propio método de llamada, anulando así el método de llamada de JavaScript? Los métodos call y apply toman como primer parámetro un objeto para especificar el contexto (este) objeto a aplicar a la invocación.

Cuestiones relacionadas