3
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。有人可以提供一些澄清吗?

4

2 回答 2

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?

与 不同xtheFunc上面将始终引用特定的函数对象。如果没有此名称,则需要额外的闭包(或使用this管道)才能递归访问该函数。此外,紧密绑定theFunc独立于当前this绑定,这可能是好是坏 - 请注意,在调用 之后setTimeouttheFunc将在不同的绑定上下文中调用(这也使得使用this.timerID怀疑)。

在 ECMAScript 第 3 版中,函数名(标识符)和 arguments.callee 将评估为范围内的相同函数对象。但是,对于 ECMAScript 第 5 版“严格”模式,arguments.callee 无效。

该名称也可能出现在堆栈跟踪toString()name/ displayName(如实施)中。


1来自ES5 注释,函数声明

可以从 FunctionExpression 的 FunctionBody 内部引用 FunctionExpression 中的标识符,以允许函数递归调用自身。

于 2013-05-17T03:27:13.800 回答
-1

在 JavaScript 中,一切都是具有成员的对象,这些成员可以根据您放入的内容作为属性或方法。

在这种情况下,timer将有一些成员用作方法(addstart)。为此,它们将包含对function代码的引用。start他为( )中的代码引用命名的唯一原因runNext是,他可以从内部再次递归调用该函数。你在里面看到的第二个函数引用runNext,是另一个匿名函数引用,它甚至没有被分配给任何东西,但它只是在那里让它在那个时刻返回一些东西runNext

于 2013-05-17T03:42:42.430 回答