2011-02-14 25 views
27

Este fragmento está cortado de Secrets of the JavaScript Ninja.¿Por qué debería usar "aplicar"?

function log() { 
    try { 
     console.log.apply(console, arguments); 
    } catch(e) { 
     try { 
      opera.postError.apply(opera, arguments); 
     } catch(e){ 
      alert(Array.prototype.join.call(arguments, " ")); 
     } 
    } 
} 

Por qué debería usar aplicar y cuál es la diferencia entre console.log.apply(console, arguments) y console.log(arguments)?

+0

La documentación debe aplicar algunos hasta cómo es especial: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/function/apply (pista: se hace algo especial con el * tipo array cosa * [ver notas] suministradas como un parámetro) –

Respuesta

11

Si tiene

function log() { 
    console.log.apply(console, arguments); 
} 

y lo llama como log('foo'); entonces que se traduce en console.log.apply(console, ['foo']); lo que equivale a console.log('foo'); que es lo que desea.

Si definió como si fuera

function log() { 
    console.log(arguments); 
} 

entonces log('foo'); sería equivalente a log(['foo']); que no es lo que desea.

6

La función apply cambia el valor de this en el destinatario y le permite pasar una matriz para los argumentos.

Por ejemplo, si quieres pasar un array como argumentos a una función:

function foo(value1, value2, value3) { 
    alert("Value 1 is "+value1+"."); 
    alert("Value 2 is "+value2+"."); 
    alert("Value 3 is "+value3+"."); 
} 
var anArray=[1, 2, 3]; 
foo(anArray); // This will not work. value1 will be anArray, and value 2 and 3 will be undefined. 
foo.apply(this, anArray); // This works, as anArray will be the arguments to foo. 

O, otro uso: cambiar this:

function Foo() { 
    this.name="world"; 
    this.sayHello=function() { 
     alert("Hello, "+this.name); 
    }; 
} 
var foo=new Foo(); 
foo.sayHello(); // This works, as this will be foo in foo's sayHello. 
var sayHello=foo.sayHello; 
sayHello(); // This does not work, as this will not be foo. 
sayHello.apply(foo, []); // This will work, as this will be foo. 
+0

En este caso, el 'this' es el mismo en ambos sentidos. – MatrixFrog

+0

Su comentario es engañoso, la razón real para usar apply es otra. * No he votado negativamente tu respuesta, solo lo he explicado ;-) – kirilloid

+0

+1 para indicar: "La función de aplicar cambia el valor de esto en el destinatario" –

36

En este caso, la función de registro puede aceptar cualquier cantidad de argumentos

Usando .apply(), no importa cuántos argumentos se pasen. Puede dar el conjunto al console.log(), y llegarán como argumentos individuales.

Así que si lo hace:

console.log(arguments) 

... en realidad estás dando console.log una sola Arguments objeto.

Pero cuando lo hace:

console.log.apply(console, arguments); 

... Es como si se les pasó por separado.

Otros ejemplos útiles del uso de .apply() como este se pueden demostrar en otros métodos que pueden aceptar un número variable de argumentos. Un ejemplo de esto es Math.max().

Una llamada típica es la siguiente:

var max = Math.max(12,45,78); // returns 78 

... donde se devuelve el número más grande.

¿Qué pasa si realmente tiene una matriz de valores de la que necesita la más grande? Puede usar .apply() para pasar la colección. Math.max pensarán que se enviaron como argumentos separados en lugar de una matriz.

var max = Math.max.apply(null, [12,45,92,78,4]); // returns 92 

Como puede ver, no es necesario saber con anticipación cuántos argumentos se aprobarán. The Array podría tener 5 o 50 elementos. Funcionará de cualquier manera.

+0

En realidad, en Firebug también puedes usar console.log (argumentos) , y esto conducirá a * casi * el mismo resultado. Pero no estoy seguro acerca de otros navegadores. – kirilloid

+0

@kirilloid: Sí, más o menos. Firebug y Chrome mostrarán el contenido del objeto Arguments, pero aún se trata como un solo argumento.Perderá el beneficio de múltiples argumentos como si lo hiciera: 'log ('value was% s', str);' donde 'str' es una variable que contiene un valor que desea incorporar a la cadena. En lugar de '" value was theValue "', obtendrá '['value was% s', 'theValue']' – user113716

+1

@ user113716 - ¿por qué es el primer argumento de 'Math.max.apply'' null'? –

0

console.log(arguments) enviaría un único argumento al console.log, la matriz de argumentos pasados ​​a su método de registro. console.log.apply(console, arguments) envía los posibles argumentos múltiples como argumentos múltiples en lugar de una única matriz.

5

Discutamos algunos antecedentes, por qué apply existen especialmente cuando tenemos el método call con una sintaxis similar.

En primer lugar tenemos que comprender algunos temas:

función variadic:

En la programación de ordenadores es una función que puede aceptar cualquier número de argumentos .

estructura de datos es de JavaScript:

en JavaScript, si se trata de datos que las estructuras de datos utilizados más comúnmente es la matriz, y en la mayoría de los casos obtenemos los datos en forma de matriz.

Ahora bien, si estamos ejecutando cualquier función variadic en javascript que nuestra llamada se verá así -

average es una función variadic, y su llamada será similar,

average(1,2,3); 
average(1); 
average(3,5,6,7,8); 

y si están recibiendo los datos en formato de matriz (en la mayoría de los casos vamos a obtener los datos en formato de matriz para las funciones variadic), de las que necesitamos para llamar a nuestra función como -

average(array[0],array[1],array[2],array[3],.... and so on) 

¿Qué pasa si tenemos una matriz con 100 elementos de longitud, lo escribimos así?

No, tenemos el método apply, que fue diseñado solo para este propósito.

average.apply(null,array);