2009-10-25 25 views
6

¿Cómo escribo una función de Javascript que acepta una cantidad variable de parámetros y reenvía todos esos parámetros a otras funciones anónimas?Cómo escribir una función JS que acepta y "reenvía" el número variable de parámetros?

Por ejemplo, considere la situación de un método que desencadena un evento:

function fireStartedEvent(a,b,c,d,e,f,g,...) { 
    for(var i = 0; i < startedListeners.length; i++) { 
     startedListeners[i](a,b,c,d,e,f,g,...); 
    } 
} 

Sobre todo porque tengo una fábrica de sucesos que genera estos métodos de incendio, estos métodos no tienen interés en saber cuántos parámetros de una determinada evento o sus controladores consumen. Así que lo tengo cableado a las 7 en este momento (a través de g). Si es menos, no hay problema. Si es más, se cortan. ¿Cómo puedo capturar y pasar todos los parámetros?

Gracias.

(Usando jQuery o cualquier otro marco Javascript no es una opción aquí.)

+0

¿Es posible pasar parámetros como una matriz en JavaScript? Eso podría hacerlo. – Cyclone

Respuesta

8

Resolviendo esto requiere el conocimiento de dos conceptos de JavaScript.

La primera es la variable local especial arguments que se puede usar para acceder a los argumentos de la función sin conocer su nombre y funciona como una matriz. Sin embargo, arguments es no un Array, sino que es "de la matriz como" - que tiene propiedades denominadas 0..n-1, donde n es el número de argumentos de la función y una propiedad length - objeto. Un uso simple demostración podría ser:

function f (a) { // can include names still, if desired 
    // arguments instanceof Array -> false (exceptions to this?) 
    var firstArg = arguments[0] 
    // a === firstArg -> always true 
    // iterate all arguments, just as if it were an Array: 
    for (var i = 0; i < arguments.length; i++) { 
     alert(i + " : " + arguments[i]) 
    } 
} 
f("a","b","c") 

La segunda característica es Function.apply que invocará una función con un contexto específico (this cuando se le llama) con argumentos que resultan de la expansión de un "array como" objeto. Pero vea.

Por lo tanto, poner juntos:

function fireStartedEvent() { 
    for(var i = 0; i < startedListeners.length; i++) { 
     // jQuery will often pass in "cute" things, such as a element clicked 
     // as the context. here we just pass through the current context, `this`, 
     // as well as the arguments we received. 
     var arg = Array.prototype.slice.call(arguments) 
     startedListeners[i].apply(this, args) 
    } 
} 

Aunque la especificación ECMAScript sólo se pide una "matriz como" objeto, Function.applyno universalmente trabajar con una "matriz como" objeto y una serie de implementaciones comunes requieren un objeto adecuado Array. La advertencia desde el enlace Function.apply:

Nota: mayoría de los navegadores, incluyendo Chrome 14 y Internet Explorer 9, todavía no aceptan matriz como objetos y se producirá una excepción [si un objeto no-Array esta pasado]. [FireFox se corrigió en la versión 4.]

Afortunadamente, hay una manera relativamente sencilla idioma para convertir un "array como" objeto en un Array (que es irónico porque Array.slicequé funciona de forma universal con una "matriz como" objeto):

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

(y luego args puede usarse universalmente en ser utilizado en Function.apply.)

+0

no parece aplicarse a lo que quiere el solicitante. – mauris

+5

Creo que esto es * exactamente * lo que quiere el asker. – bcat

+0

Gracias, pst. El documento al que se vincula es excelente. Me debatí entre marcar la tuya o la respuesta de Lauri como la respuesta aceptada porque se tomó el tiempo para aplicarla a mi pregunta original. Fue un lanzamiento de moneda. Espero que entiendas. –

5

creo "aplicar" y "argumentos" son dos conceptos de JavaScript se puede utilizar aquí:

function fireStartedEvent() { 
    for (var i = 0; i < startedListeners.length; i++) { 
    startedListeners[i].apply(startedListeners[i], arguments); 
    } 
} 

Aquí hay un código de mi consola de Firebug He intentado esto con:

a = function(foo) { alert('a: ' + foo); }; 
b = function(foo, bar) { alert('b: ' + foo + ', ' + bar); }; 

startedListeners = [a, b]; 

function fireStartedEvent() { 
    for (var i = 0; i < startedListeners.length; i++) { 
    startedListeners[i].apply(startedListeners[i], arguments); 
    } 
} 


fireStartedEvent('one', 'two'); 
+0

Este código no es correcto. argumentos es similar a una matriz. No es "una matriz". apply toma una matriz como el segundo parámetro. –

+0

pst, parece funcionar para mí, ya que el método invocado utilizando apply (null, arguments) se llama y parece reconocer todos los argumentos distintos. ¿Hay algún problema que me pierda? –

+0

@pst - No sabía esto - ¿tiene un ejemplo en el que la función que publiqué no funciona? –

Cuestiones relacionadas