Pergunta

Como posso escrever uma função JavaScript que aceita um número variável de parâmetros, e encaminha todos esses parâmetros para outras funções anônimas?

Por exemplo, considere o cenário de um método que dispara um 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,...);
    }
}

Especialmente porque eu tenho uma fábrica de evento que gera esses métodos de incêndio, estes métodos não têm interesse em saber quantos parâmetros de um determinado evento ou seus manipuladores de consumir. Então, eu tenho-o hard-wired em 7 agora (A a G). Se for menos, não há problema. Se é mais, eles são cortados. Como posso simplesmente captura e passar todas parâmetros?

Graças.

(Usando jQuery ou qualquer outro framework Javascript não é uma opção aqui.)

Foi útil?

Solução

Resolver este requer o conhecimento de dois conceitos de JavaScript.

O primeiro é o especial arguments variável local que pode ser usado para acessar os argumentos da função sem saber seu nome e ele funciona como um array. No entanto, arguments é não um Array, mas é "matriz como" - tendo propriedades chamado 0..n-1, onde n é o número de argumentos para a função e uma propriedade length - objeto. A utilização simples demonstração pode 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")

A segunda característica é Function.apply que irá invocar uma função com um contexto específico (this quando é chamado) com argumentos que resultam da expansão de uma "matriz como" objeto. Mas veja 1 .

Assim, colocá-lo 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)
    }
}

1 Embora a especificação ECMAScript chamadas apenas para um "array como" objeto, Function.apply não universalmente trabalho com uma "matriz como" objeto e uma série de implementações comuns requerem um objeto Array adequada. O aviso a partir do link Function.apply:

Nota: A maioria dos navegadores, incluindo o Chrome 14 e Internet Explorer 9 , ainda não aceitam matriz como objetos e irá lançar uma exceção [se um não- objeto de matriz é passado]. [FireFox foi corrigido na versão 4.]

Felizmente, há uma forma relativamente simples linguagem para transformar um "array como" objeto em um Array (que é irônico, porque Array.slice faz universalmente trabalho com uma "matriz como" objeto):

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

(E então args pode ser universalmente utilizado em ser usado em Function.apply.)

Outras dicas

Eu acho que "aplicar" e "argumentos" são dois conceitos JavaScript você pode usar aqui:

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

Aqui está um código de minha Firebug consola Eu tentei isso com:

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');
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top