JavaScriptのコールバック関数の理解を深める


163

関数をコールバックとして別の関数に渡し、それを実行させることは理解していますが、それを行うための最適な実装を理解していません。次のような非常に基本的な例を探しています。

var myCallBackExample = {
    myFirstFunction : function( param1, param2, callback ) {
        // Do something with param1 and param2.
        if ( arguments.length == 3 ) {
            // Execute callback function.
            // What is the "best" way to do this?
        }
    },
    mySecondFunction : function() {
        myFirstFunction( false, true, function() {
            // When this anonymous function is called, execute it.
        });
    }
};

myFirstFunctionで、new callback()を返す場合、それは機能し、無名関数を実行しますが、それは私にとって正しいアプローチのようには見えません。


どのような意味で正しいですか?通常、コールバックはイベントハンドラー、特に非同期のAjax呼び出しに使用されます。基本的には、応答がいつ(またはいつ)発生するかわからないものです。
cletus 2009年

2
ちなみに、引数はarrayではなくarrayなので、argument.lengthは実行できませんが、sliceメソッドを使用して配列に変換できます...
paul

1
@paul、あなたは正しいarguments配列ではありませんが、その長さを参照することができますarguments.length-試してみてください。このプロパティは、実際に渡された引数の数を参照しますが、関数シグネチャのパラメーターの数を参照する必要はありません。
hotshot309

回答:


132

あなたはただ言うことができます

callback();

または、コールバック内ののcall値を調整する場合は、このメソッドを使用できthisます。

callback.call( newValueForThis);

関数の中身はthis何でもかまいませんnewValueForThis


91

コールバックが存在し、実行可能関数であるかどうかを確認する必要があります。

if (callback && typeof(callback) === "function") {
    // execute the callback, passing parameters as necessary
    callback();
}

ライブラリ(jQueryの、道場、等)多くのそれらの非同期機能のために同様のパターンを使用し、ならびにすべての非同期機能のためのNode.js(通常通過nodejs error及びdataコールバック)。彼らのソースコードを調べることは助けになるでしょう!


なぜcallback文字列にキャストしてからその型をチェックするのですか?これによりパフォーマンスが向上しますか?これは、タイプをチェックし、変換されたブール値がtrueを返すかどうかをチェックしてから、そのタイプを再度チェックして、文字列に対してテストするようなものです...理由を説明してください。
headacheCoder

コールバックに最初のアサーションが必要な理由に興味があります... nullまたは未定義をチェックするのですか?typeof(callback)あなたのためにそれを達成しませんか? typeof(null) === "Object"typeof("undefined") === "undefined"
PJH 2014年

1
ANDを短絡します。コールバックが存在しない場合は、そのタイプを計算する必要はありません。しかし、あなたは正しいです。typeof()では必要ありませんが、jsperfを実行して、短絡の価値があるかどうかを確認します。
arunjitsingh 2014年

@headacheCoder- callback文字列にキャストされておらず、そのタイプは、呼び出される前に関数かどうかをチェックされます。コードはおそらくcallback引数として受け入れ、引数が呼び出し可能な型であることは不明です。あるいは、引数がさまざまな型であり、コードが異なるtypeof引数に対して異なる反応をする可能性がある多態性の形式を提供しようとしている可能性があります。
LeeGee

34

関数を実行するには、主に3つの可能性があります。

var callback = function(x, y) {
    // "this" may be different depending how you call the function
    alert(this);
};
  1. callback(argument_1、argument_2);
  2. callback.call(some_object、argument_1、argument_2);
  3. callback.apply(some_object、[argument_1、argument_2]);

選択する方法は、次のいずれかによって異なります。

  1. 引数が配列に格納されているか、個別の変数として格納されています。
  2. あるオブジェクトのコンテキストでその関数を呼び出したいとします。この場合、そのコールバックで「this」キーワードを使用すると、call()またはapply()で引数として渡されたオブジェクトが参照されます。オブジェクトコンテキストを渡したくない場合は、nullまたはundefinedを使用します。後者の場合、「this」にはグローバルオブジェクトが使用されます。

Function.callFunction.applyのドキュメント


6

コールバックはシグナルに関するものであり、「新規」はオブジェクトインスタンスの作成に関するものです。

この場合、「callback();」だけを実行するのがさらに適切です。「return new callback()」よりも、とにかく戻り値で何もしていません。

(そして、arguments.length == 3テストは本当に不格好です、fwiw、コールバックparamが存在し、関数であることを確認する方が良いです。)


6

適切な実装は次のとおりです。

if( callback ) callback();

これにより、コールバックパラメータがオプションになります。


コールバック引数が関数でない場合はどうなりますか?
Yaki Klein

2

以下を使用できます。

if (callback && typeof(callback) === "function") {
    callback();
}

以下の例はもう少し包括的です:

function mySandwich(param1, param2, callback) {
  alert('Started eating my sandwich.\n\nIt has: ' + param1 + ', ' + param2);
  var sandwich = {
      toppings: [param1, param2]
    },
    madeCorrectly = (typeof(param1) === "string" && typeof(param2) === "string") ? true : false;
  if (callback && typeof(callback) === "function") {
    callback.apply(sandwich, [madeCorrectly]);
  }
}

mySandwich('ham', 'cheese', function(correct) {
  if (correct) {
    alert("Finished eating my " + this.toppings[0] + " and " + this.toppings[1] + " sandwich.");
  } else {
    alert("Gross!  Why would I eat a " + this.toppings[0] + " and " + this.toppings[1] + " sandwich?");
  }
});


1

callback()JavaScript の関数を説明する基本的な例を次に示します。

var x = 0;

function testCallBack(param1, param2, callback) {
  alert('param1= ' + param1 + ', param2= ' + param2 + ' X=' + x);
  if (callback && typeof(callback) === "function") {
    x += 1;
    alert("Calla Back x= " + x);
    x += 1;
    callback();
  }
}

testCallBack('ham', 'cheese', function() {
  alert("Function X= " + x);
});

JSFiddle


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.