解决这个问题需要了解两个 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。)