6

如何编写一个接受可变数量参数并将所有这些参数转发给其他匿名函数的 Javascript 函数?

例如,考虑触发事件的方法的场景:

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,...);
    }
}

特别是因为我有一个生成这些触发方法的事件工厂,这些方法对知道给定事件或其处理程序消耗多少参数没有兴趣。所以我现在把它固定在 7 点(a 到 g)。如果再少一点也没问题。如果还有的话,他们就会被切断。我怎样才能捕获并传递所有参数?

谢谢。

(这里不能选择使用 jQuery 或任何其他 Javascript 框架。)

4

2 回答 2

8

解决这个问题需要了解两个 JavaScript 概念。

第一个是特殊的arguments局部变量,可用于在不知道其名称的情况下访问函数参数,它像数组一样工作。但是,arguments不是,而是Array“类似数组”——具有名为 的属性0..n-1,其中n是函数的参数数量和length属性——对象。一个简单的演示用法可能是:

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")

第二个功能是Function.apply调用具有特定上下文(this当它被调用时)的函数,其参数来自“类数组”对象的扩展。但见1

因此,将其放在一起:

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虽然 ECMAScript 规范只要求“类似数组”的对象,Function.apply 但并不普遍适用于“类似数组”的对象,并且许多常见的实现都需要适当的Array对象。Function.apply来自链接的警告:

注意:大多数浏览器,包括Chrome 14Internet Explorer 9,仍然不接受类似数组的对象,并且会抛出异常 [如果传递了非数组对象]。[FireFox 在版本 4 中已修复。]

值得庆幸的是,有一个相对简单的习语可以将“类似数组”的对象变成一个Array(具有讽刺意味的是,Array.slice 普遍适用于“类似数组”的对象):

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

(然后args可以通用于被用在Function.apply。)

于 2009-10-25T03:01:08.367 回答
5

我认为“应用”和“参数”是您可以在这里使用的两个 JavaScript 概念:

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

这是我尝试使用的 Firebug 控制台中的一些代码:

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');
于 2009-10-25T03:04:47.393 回答