2011-02-04 28 views
2

配列内の各要素のプロパティとして関数を設定したいが、異なる引数で呼び出す。私は匿名関数を使用してそれを解決しようと思いました:匿名関数のJavaScriptコンテキスト

for (var i = 0; i < object_count; i++) { 
    objects[i].callback = function(e,x,y){ cb(e,x,y,i) }; 
} 

しかし、機能がiは一度に持っている値と呼ばれています。私はどのようにして文脈を保存するだろうか?

+1

'i'を宣言時に関数に配置するのではなく、引数にしますか? –

+0

なぜあなたは最初に 'cb()'に 'i'を提供しますか?グローバル配列でなければ関数は配列の他の要素にアクセスすることはできませんが、その場合は要素*関数ごとにこの*は必要ありません。 –

+0

@ブラッド:ティムは問題を解決するあなたの提案に満足するかもしれないが、彼は彼のコードとは別の問題があるかもしれないので、答えにそれを入れてください。 –

答えて

10

あなたは機能の代入、または右辺少なくともラップすることができます:「外側」無名関数は、「i」は、引数にループ変数をコピーし、すぐに呼ばれ

objects[i].callback = (function(i) { return function(e, x, y) { 
     cb(e, x, y, i); 
    })(i); 

を(私は「i」とも呼ばれますが、他の人は混乱していると言う人もいますが、ではなくとすることができますので、返す「内部」匿名関数によって使用されます。

この問題の別のアプローチは、単純なインライン匿名関数ではなく、この目的のためにユーティリティ関数を使用することです。この場合、「i」が実際のコールバック関数のの最後のパラメータになりたいから少し微妙になります。 Functional JavaScriptライブラリには、関数の選択された引数を固定値で "事前に設定"できるクールなユーティリティがあり、固定されていない引数に引数を渡すことができる関数を提供します。

objects[i].callback = (function(e, x, y, i) { return cb(e, x, y, i); }).partial(_, _, _, i); 

これは良いか悪いかは、スタイルや意見の問題です。

編集ちょっとコーヒーがありました - 私は上記の「部分」を使用しなければならないと少し馬鹿に思っていたと思います。内部( "実際の"関数)がパラメータリストの最後に "i"を必要としているという事実は、設定が必要な方法に実際には関係ありません。上記の例は、次のようにすることもできます:

objects[i].callback = (function(i, e, x, y) { return cb(e, x, y, i); }).curry(i); 

これはちょっと奇妙です。 (どちらか一方が働くだろう。少なくとも、私は彼らはと思います。:-)

+2

+1私は外側の無名関数を 'for'ループの外に作成したいと思います。 – lonesomeday

+0

+1オシャレ、オハイオ州閉鎖が大好き – aorcsik

+0

@lonesomeday - はい私は同意します。私はこれを '.bind()'またはそれに似たもので行うことを好むでしょう。私は答えにその言及を追加します。 – Pointy

3

あなたの機能で

for (var i = something; ...) { 
    a[i] = function() { x(i); } 
} 

iは、すべての機能のために同じになります書くとき(それはあなたの非常に同じ変数ですあなたのforループの範囲に定義します。あなたが何をしたいのか

は、各機能のコンテキストに固有だ変数を持つことです。あなたはこの

for (var i = something; ...) { 
    (function() {  // using an anonymous function, we create a private context 
    var new_i = i;  // new_i has the value of 'i' but exists solely in this 
         // private context 
    a[i] = function() { x(new_i); } 
         // the assigned function now refers a variable of the private 
         // context, which will be different on the following loop 
         // iterations 
    })(); 
} 
のような何かを行うことができます

JavaScriptでクロージャとスコープがどのように機能するかを調べることで、このトピックの詳細を得ることができます。

+0

私はPointyのソリューションがよかったと思います。それは非常に似たような方法でそれを解決しますが、短くてウィッティアです。 ;)それでも問題を解決するので、私からの+1はまだあります。 –