如何编写一个接受可变数量参数的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框架不是一个选项.)
解决这个问题需要了解两个JavaScript概念.
第一个是特殊的arguments
局部变量,可用于在不知道其名称的情况下访问函数参数,它的工作方式类似于Array.但是,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 14和Internet Explorer 9)仍然不接受类似对象的数组,并且会抛出异常[如果传递非Array对象].[FireFox在版本4中得到修复.]
幸运的是,有一个相对简单的成语打开"阵列状"对象到一个Array
(这是因为具有讽刺意味Array.slice
不普遍与"阵列状"对象工作):
var args = Array.prototype.slice.call(arguments);
(然后args
可以普遍用于Function.apply
.)
我认为"apply"和"arguments"是你可以在这里使用的两个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');