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

これで、上記の関数に 1 つずつフィードする必要があるオブジェクトの配列 ( 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れている無名関数内から実際に呼び出されます。これは ECMAScript/Javascript で合法ですか? (標準に準拠したすべてのブラウザで動作するという法的意味)WorkFunc

つまり、私にとっては、 JavascriptC/C++/ObjC/Javaとほとんど同じvar c = c + 1;、定義中に変数を参照しているため、違法である、動作が undefined である必要があります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解決策 3: 内部を参照する必要がないように、変数をパラメーター ( ) として渡します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.

しかし、私の質問はまだ残っています: 私の元の解決策は合法でしたか?

4

1 に答える 1

1

はい。匿名関数は、値に関係なく、親スコープで宣言されたすべての変数にアクセスできます (これは、匿名関数で再帰を行う標準的な方法です)。

後で親スコープで変数を null に設定すると、無名関数の後続の呼び出しで TypeError がスローされることに注意してください (null はもう呼び出せなくなるため)。これは、その値を変更して別の関数をターゲットにすることもできることを意味します (ただし、これは良い習慣ではありません)。

于 2012-11-15T02:42:06.553 に答える