2

私は最近多くの JavaScript を学んでいますが、私がよく理解していないことの 1 つは、関数をパラメーターとして他の関数に渡すことです。そのようなことをするという概念は理解できますが、私自身はこれが理想的な状況を思いつくことができません。

私の質問は:

JavaScript 関数に別の関数をパラメーターとして使用させたいのはいつですか? その関数の戻り値に変数を割り当てて、その変数を次のように関数に渡すだけではどうですか。

// Why not do this
var foo = doStuff(params);
callerFunction(foo);

//instead of this
callerFunction(doStuff);

なぜ私が 2 番目の例のように物事を行うことを選択するのか、私は混乱しています。

なぜこれを行うのですか?ユースケースにはどのようなものがありますか?

4

10 に答える 10

3

ハンドラー/リスナーが良い例です。

より一般的には、関数 g が f を呼び出す必要があるかどうか、呼び出す必要がある回数、および/またはどのパラメーターを使用する必要があるかがまだわからない場合は、関数 f をパラメーターとして関数 g に渡すことができます。

例:

  • 並べ替えアルゴリズム: 比較関数
  • 正規表現: 置換関数
  • コールバック (イベント ハンドラなど)
于 2012-11-06T22:54:48.587 に答える
3

さらに別の例を示します。配列に対していくつかのフォーマット操作を行います。

function pctFormatter(num) {
  return num + '%';
}

function centsFormatter(num) {
  return num + '.00';
}

function formatThisArray(array, formatter) {
  var output = [];
  for(var i = 0; i < array.length; i++) {
    output.push( formatter(array[i]) );
  }
  return output;
}

formatThisArray([1,2,3], pctFormatter);// returns ['1%', '2%', '3%']
formatThisArray([1,2,3], centsFormatter);// returns ['1.00', '2.00', '3.00']
于 2012-11-06T22:56:06.917 に答える
2

パスする必要がない場合は実行しますが、paramsパスは実行callerFunction()します。

AJAX リクエストへのコールバックは、1 つのユース ケースです。

function myCallback(response) {
    // do something with the response
}

myAJAX('http://example.com/foo.json', myCallback)

これによりmyAJAX、リクエストを作成し、レスポンスを待つ作業が開始されます。myCallback次に、その応答が最終的に到着したときに、応答を呼び出して渡します。

于 2012-11-06T22:49:28.530 に答える
1
// Why not do this
var foo = doStuff(params);
callerFunction(foo);

//instead of this
callerFunction(doStuff);

最初の例では、で関数doStuffを実行しparams、結果を に代入しfooます。callerFunctionパラメーターを指定して呼び出されますfoo(これは の結果ですdooStuff);

2 番目の例では、パラメーターとして呼び出しcallerFunctionて渡しdoStuffます。はcallerFunctionを呼び出す場合と呼び出さない場合がありますdoStuff

于 2012-11-06T22:52:53.367 に答える
1

関数が呼び出されるまで、関数の呼び出し元が誰になるかわからない場合があります。これにより、事前に計算された値を渡すことができなくなります。

頭に浮かぶいくつかの例は次のとおりです。

(a) setTimeout または setInterval - ワンショットまたは繰り返しのいずれかで、指定された期間の後に特定の関数を呼び出したい場合。呼び出された関数が時間に依存する値を返した場合、値を事前に計算できない場合があります。スケジュールされた時間に計算を行う必要があります。したがって、指定された時間に呼び出す独自の関数を関数に指示します。

(b)さまざまなリソースをロードする(または少なくとも試行する)とき。ロードが成功したときに実行される関数と、失敗したときに実行される関数を要素に与えることができます。これら 2 つの (ユーザー提供の) 関数のいずれかが呼び出されるまで、リソースをロードする作業がいつ終了したかは実際にはわかりません。多くのリソースの場合、これは、成功/失敗した読み込み試行の数を維持するカウンターをインクリメントする場所です。

(c) getElementsByClass または getElementsByTagName の呼び出しによって返される NodeList。実際の (javascript ネイティブ) Array オブジェクトではありません。そのため、配列のように forEach メソッドを呼び出すことはできません。これを回避するために、次のヘルパー関数を使用します。

// getElementsByTagName, getElementsByClass - both return a NodeList
// it is accessed in the same way as an array - with the [] operators, but it's
// not an array object - this is a function that allows us to still iterate through it
// in much the same way.
function forEachNode(nodeList, func)
{
    var i, n = nodeList.length;
    for (i=0; i<n; i++)
    {
        func(nodeList[i], i, nodeList);
    }
}

これにより、ノードのリストを取得し、それぞれのユーザー定義関数を呼び出すことができます。使用中は、次のようになります。

var allAnchors = document.getElementsByTagName('a');
forEachNode(allAnchors, showNodeTextVal);
function showNodeTextVal(curElem, curIndex, origList)
{
  alert(curElem.innerText);
}

またはもっと簡単に:

var allAnchors = document.getElementsByTagName('a');
forEachNode(allAnchors, function(curElem){alert(curElem.innerText);} );

これは、このヘルパー関数を使用しない場合よりもはるかに明確で、エラーが発生しにくい状況です。同じ機能を実現するには、次のようにコーディングする必要があります。

var nodeList = document.getElementsByTagName('a');
var i, n = nodeList.length;
for (i=0; i<n; i++)
{
  alert(nodeList[i].innerText);
}
于 2012-11-06T23:04:36.967 に答える
0
callerFunction(doStuff);

doStuffこのコードでは、関数への関数の「ポインタ」を与えますcallerFunction

次のように使用できます。

function callerFunction(doStuff) {

   var x = doStuff(...);
   ...;
}

の戻り値だけでなく、関数内で関数を使用することもできますdoStuff

ご挨拶!

于 2012-11-06T22:53:01.813 に答える
0

JavaScript 関数に別の関数をパラメーターとして使用させたいのはいつですか?

たとえば、コールバックに役立ちます。

function add( a, b, callback ) {
  callback( a, b );
  return a + b;
}

function added( a, b ) {
  alert('You just added two numbers: '+ a +' and '+ b);
}

alert( add( 1, 2, added ); // Will alert the message and then the result.

これは非常に単純な例ですが、スクリプトを中断することなく終了後にコードを実行できるように、非同期関数で非常に便利です。

于 2012-11-06T22:53:55.713 に答える
0

コードで実際に関数を関数として処理する場合 (実行するコード) は、戻り値ではなく、関数自体を渡す必要があります。次の疑似コードの例を検討してください。

function saveToLocalStorage(data) {...//saves to local storage}

function saveToServer(data) {...//saves via AJAX to server}

function saveToAmazonS3(data) {.../saves to Amazon S3 }

function multiSave(data, saverFunctions) {
    saverFunctions.forEach(function (saverFunction) {
      saverFunction(data);
    });
}

multiSave({user: "tim"}, [saveToLocalStorage, saveToServer, saveToAmazonS3]);

この場合、実際の関数自体が渡され、他のコードが後でそれらを呼び出すようにしたいと考えています。このとき、 のような関数multiSaveは、他の関数を直接扱うため、高階関数と呼ばれます。multiSave の仕組みのおかげで、ローカル/サーバー/S3 の隣の UI にいくつかのチェックボックスを簡単に配置して、ユーザーがデータの移動先を選択できるようにすることができます。引数。

于 2012-11-06T22:55:06.337 に答える
0

関数を引数として渡す場合、その引数はその関数の戻り値ではなく、関数自体です。好きなだけ、好きな引数で呼び出すことができます。イベント。
いくつかの実用的なユースケースが必要だと言うと、ここに非常に一般的な状況の短いリストがあり、すべて関数を引数として渡す必要があります。

平均的な jQuery コードを見て、関数が引数として渡される回数を数えてみましょう。

$(document).ready(function()//<-- 1
{
    $('#foo').on('click',function()//2
    {
    });
    $.each(something,function()//3
    {});
    //and so on
});

jQuery を使用しない場合は、イベント委任を試してください

document.body.addEventListener('click',function(e)
{
    e = e || window.event
    console.log('This function was passed as an argument to the addEventListener method');
},false);

または単純なArray.prototype.sort関数 (/method):

anArray.sort(function(a,b)
{
    return (a > b ? 1 : -1);
});

または、その場で新しいオブジェクトを作成する代わりに、ajax 呼び出しを行う必要がある場合はXMLHttpRequest、xhr オブジェクトを設定し、URL、データ、およびonreadystatechangeコールバックを引数として渡す単一の関数が必要になる場合があります。

function makeXHR(url,data,callback)
{
     try
     {
          var xhr = new XMLHttpRequest();
      }
      catch(e)
      {
           //etc...
      }
      xhr.onreadystatechange = callback;
}
makeXHR('some/url','foo=bar',function()
{
    if (this.readyState === 4 && this.status === 200)
    {
        //do stuff
    }
});

これらの例のすべてで、関数をインラインで作成しました。もちろん、関数の参照 (名前を渡すだけ) も問題なく機能します。

makeXHR('some/url','foo=bar',defaultXhrCallback);

これらは、関数を引数として別の関数に渡すことができる/渡す必要がある数千のユースケースのほんの一部です

于 2012-11-06T22:59:53.217 に答える
0

最も一般的なケースは、JQuery のハンドラーです。

function clickHandler(e){
  // handle click on e.Target
}

$("#button").click(clickHandler);

$(function(){
// do ready state initialization
});
于 2012-11-06T22:49:05.770 に答える