質問

I am given a function like this:

//! 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. */
}

Now, I have an array of objects (RecordArray) that I need to feed to the above function, one by one, meaning that I have to wait until it callbacks before calling it the next time.

So I came up with:

$(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.
});

As you can see, WorkFunc is actually called from within the anonymous function on which the variable WorkFunc itself is defined. Is this legal in ECMAScript/Javascript? (legal meaning that it works on all standard-compliant browsers)

I mean, to me, it is pretty much like var c = c + 1; in Javascript or int c = c + 1; in C/C++/ObjC/Java, which is referencing a variable while defining it, so either it should be illegal or it's behaviour should be undefined.

However, it seems to work fine on a few browsers.


After some more research and thinking, I came up with other solutions.

  • Solution 1: Naming the anonymous function (MyFunc), so that I can use its name inside (reference here).

Code:

var WorkFunc = function MyFunc() {  // Name it MyFunc.
    if(RecordIndex < RecordArray.length)
    {
        WorkOnRecord(RecordArray[RecordIndex], function() {
            MyFunc();   // Use MyFunc here
        });
        RecordIndex++;
    }
};
WorkFunc();
  • Solution 2: Use a function declaration instead of a function expression, so that it is more like a recursive function (although not exactly) (reference here).

Code:

function WorkFunc() {   // Declare function.
    if(RecordIndex < RecordArray.length)
    {
        WorkOnRecord(RecordArray[RecordIndex], function() {
            WorkFunc();
        });
        RecordIndex++;
    }
};
WorkFunc();
  • Solution 3: Passing the variable as a parameter (NextStepFunc), so that I don't need to reference WorkFunc inside (this looks so funny).

Code:

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.

But my question still stands: was my original solution legal?

役に立ちましたか?

解決

Yes. The anonymous function can access to every variable declared in parent scopes, regardless their value (that's the standard way to make recursion with anonymous functions).

Note that if you set the variable to null later in the parent scope, subsequents calls in the anonymous function will throw a TypeError (because null will not be callable anymore). It also means that you could even change its value to target another function (but it's definitely not a good practice).

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top