JavaScript:将变量定义为调用相同函数的匿名函数

3

我得到了一个像这样的函数:

//! Work on record.
/*!
    \param[in]  Record                  (object) Record.
    \param[in]  AsyncCallback           (function) Asynchronous callback which is called when the operation is complete. It takes no parameters.
*/
function WorkOnRecord(Record, AsyncCallback)
{
    /* Work on Record asynchronously (e.g. by calling $.ajax())
       and call AsyncCallback on complete. */
}

现在我有一个对象数组(RecordArray),我需要逐个将它们传递给上面的函数,也就是说我必须等待回调后再次调用它。因此我想到了以下方法:
$(function() {
    var RecordArray = SomeOtherFunc();      // RecordArray is an array of objects.

    // Work on records, one by one.
    var RecordIndex = 0;
    var WorkFunc = function() {
        // If there are still records to work on...
        if(RecordIndex < RecordArray.length)
        {
            // Work on record.
            WorkOnRecord(RecordArray[RecordIndex], function() {
                // Move forward to next record.
                WorkFunc();
            });
            RecordIndex++;
        }
        // If there are no more records to work on...
        else
        {
            /* We are all done. */
        }
    };
    WorkFunc(); // Start working.
});

如您所见,WorkFunc 实际上是从定义变量 WorkFunc 的匿名函数内部调用的。这在 ECMAScript/Javascript中是否合法?(合法意味着它可以在所有符合标准的浏览器上工作)
我的意思是,对我来说,这很像Javascript中的 var c = c + 1; 或者 C/C++/ObjC/Java 中的 int c = c + 1;,即在定义时引用变量,因此要么应该是非法的,要么其行为应该是未定义的。
但是,在一些浏览器上似乎可以正常工作。
更多研究和思考后,我想到了其他解决方案。
解决方案1:给匿名函数(MyFunc)命名,这样我就可以在内部使用它的名称 (参考这里)。
代码:
var WorkFunc = function MyFunc() {  // Name it MyFunc.
    if(RecordIndex < RecordArray.length)
    {
        WorkOnRecord(RecordArray[RecordIndex], function() {
            MyFunc();   // Use MyFunc here
        });
        RecordIndex++;
    }
};
WorkFunc();
  • 解决方案2:使用函数声明代替函数表达式,这样更像是一个递归函数(虽然不完全相同)(参考此处)。

代码:

function WorkFunc() {   // Declare function.
    if(RecordIndex < RecordArray.length)
    {
        WorkOnRecord(RecordArray[RecordIndex], function() {
            WorkFunc();
        });
        RecordIndex++;
    }
};
WorkFunc();
  • 解决方案三:将变量作为参数(NextStepFunc)传递,这样我就不需要在内部引用WorkFunc(这看起来很有趣)。

代码:

var WorkFunc = function(NextStepFunc) { // Accept function as parameter.
    if(RecordIndex < RecordArray.length)
    {
        WorkOnRecord(RecordArray[RecordIndex], function() {
            NextStepFunc(NextStepFunc); // Call function as defined by parameter.
        });
        RecordIndex++;
    }
};
WorkFunc(WorkFunc); // Pass function as variable to parameter.

但是我的问题依然存在:我的原始解决方案是否合法

2
是的,这是合法的。该函数闭合在WorkFunc变量本身上,而不是值,因此当函数被调用时,它获取当前值,即函数本身。 - I Hate Lazy
1
我只是担心这里会出现回调地狱...但我更喜欢解决方案一。 - Thalaivar
如果你没有传递任何参数,可以这样做:WorkOnRecord(RecordArray[RecordIndex], WorkFunc)(或者如果参数来自于WorkOnRecord,也可以这样做)。顺便说一句,FWIW。 - I Hate Lazy
正如已经说明的那样,使用原始方法并没有问题。解决方案2基本上与您的原始方法相同 - 有一些差异太复杂了无法在评论中解释,但对于这种情况无关紧要。 (请看这个。) - nnnnnn
1个回答

1

是的。匿名函数可以访问在父级作用域中声明的每个变量,无论它们的值如何(这是使用匿名函数进行递归的标准方式)。

请注意,如果您稍后在父级作用域中将变量设置为null,则匿名函数中的后续调用将抛出TypeError(因为null将不再可调用)。这也意味着您甚至可以更改其值以针对另一个函数(但这绝对不是一个好习惯)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接