解决这个问题需要了解两个 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 14和Internet Explorer 9,仍然不接受类似数组的对象,并且会抛出异常 [如果传递了非数组对象]。[FireFox 在版本 4 中已修复。]
值得庆幸的是,有一个相对简单的习语可以将“类似数组”的对象变成一个Array
(具有讽刺意味的是,Array.slice
它普遍适用于“类似数组”的对象):
var args = Array.prototype.slice.call(arguments);
(然后args
可以通用于被用在Function.apply
。)