var timers = { //#1
timerID: 0, //#2
timers: [], //#2
add: function(fn) { //#3
this.timers.push(fn);
},
start: function runNext() { //#4
if (this.timerID) return;
(function() {
if (timers.timers.length > 0) {
for (var i = 0; i < timers.timers.length; i++) {
if (timers.timers[i]() === false) {
timers.timers.splice(i,1);
i--;
}
}
timers.timerID = setTimeout(runNext, 0);
}
})();
},
上面的代码来自John Resig的 JavaScript Ninja的秘密。我不明白的部分是他将函数赋给start
的属性,然后命名函数runNext
。有人可以提供一些澄清吗?
答案 0 :(得分:2)
函数的“名称”也起到特殊作用,在FunctionExpression 1 中使用时特别有用:
x = function theFunc (z) {
// theFunc is in scope here, and so can be used to refer
// to the function itself in a recursive manner
// (in the posted code it is used with setTimeout)
return z > 0 ? theFunc(z - 1) * z : 1;
};
// theFunc is NOT in scope here in valid ECMAScript; IE quirks anyone?
与x
不同,上面的theFunc
总是指的是特定的函数对象。如果没有此名称,则需要额外的闭包(或使用this
管道)来递归访问该函数。此外,紧密绑定使theFunc
独立于当前this
绑定,这可能是好的或坏的 - 请注意,在调用setTimeout
后,theFunc
将被调用一个不同的绑定上下文(也使用this.timerID
可疑)。
在ECMAScript第3版中,函数名(Identifier)和arguments.callee将评估范围内的同一函数对象。但是,根据ECMAScript第5版“严格”模式,arguments.callee无效。
该名称也可能显示在堆栈跟踪中,toString()
和name
/ displayName
(已实施)。
1 来自ES5 Annotated, Function Declarations:
可以从FunctionExpression的FunctionBody内部引用FunctionExpression中的标识符,以允许函数递归调用自身。
答案 1 :(得分:-1)
在JavaScript中,一切都是具有成员的对象,这些成员可以根据您放入的内容作为属性或方法。
在这种情况下,timer
会有一些成员将用作方法(add
和start
)。为此,它们将包含对function
代码的引用。他在start
(runNext
)中为代码引用命名的唯一原因是他可以从内部再次递归调用该函数。您在runNext
中看到的第二个函数引用是另一个匿名函数引用,它甚至没有被赋值给任何东西,但它只是让它在那时为runNext
返回一些东西。