21

JavaScriptで動的に作成された "a"タグのonclickイベントに関数を割り当てることを試みてきました。ループ内の関数(別の関数を返す)はどのように機能しますか?

for (var i = 0; i < 4; i++) 
{ 
    var a = document.createElement("a"); 
    a.onclick = function() { alert(i) }; 
    document.getElementById("foo").appendChild(a); 
} 

すべての4つのリンクのための警告値は常に「4」で次のようにタグのすべてがループ内に作成されます。かなり明白。グーグルとき私は、次のコードスニペットを示してポストに出くわした:

a.onclick = (function(p, d) { 
return function(){ show_photo(p, d) } 
})(path, description); 

私は私のニーズのためにそれを微調整するために管理し、アラート(I)のものが正常に動作するようになった誰かが正確に説明することができる場合、私は感謝します上記のコードは何をしますか?

+0

こんにちは:

私は、クロージャ(およびcurryの非常に基本的な考え方を)説明するために、次のコードを使用するには、私は簡単な例は、概念を得るために簡単に作ることができると思いますアラート "4"?それは "2"ではないでしょうか?ありがとう。 – Tarik

+0

for(var i = 0; i <3; i ++)は、最後にi == 4を残します。 –

+1

いいえ、私は3をそのまま残します。 –

答えて

45

:あなたの問題は、関数を返す関数を使用することです。

基本的には、関数をネストするときにクロージャが作成されます。内部関数は、親関数が既に実行された後でも、それらの外側の囲み関数に存在する変数を参照できます。

clickイベントが実行された時点で、ハンドラは、その変数がクロージャに格納されているため、変数の最後の値を参照します。あなたが気づいたよう

、別の関数を引数としてi変数を受け入れるためにクリックハンドラ関数をラップし、返すことによって、それはあなたが期待するように動作(基本的には別のクロージャを作成する):

for (var i = 0; i < 4; i++) { 
    var a = document.createElement("a"); 
    a.onclick = (function(j) { // a closure is created 
    return function() { 
     alert(j); 
    } 
    }(i)); 
    document.getElementById("foo").appendChild(a); 
} 

あなたを実際には4つの関数を作成し、それぞれの関数は(iを渡すことによって)作成された時点でiへの参照を格納します。この値は、外側のクロージャに格納され、内部の関数はclickイベントが発生したときに実行されます。なぜそれあなたが私に言うことができる、

// a function that generates functions to add two numbers 
function addGenerator (x) { // closure that stores the first number 
    return function (y){ // make the addition 
    return x + y; 
    }; 
} 

var plusOne = addGenerator(1), // create two number adding functions 
    addFive = addGenerator(5); 

alert(addFive(10)); // 15 
alert(plusOne(10)); // 11 
+3

テイラー、私はあなたに満足しています。私はあなたに仕上げさせてもらいますが、この投稿はいつも最高です。 – Tarik

+0

あなたは42kポイントを持っているのも不思議ではありません:) –

+4

私は持っていたように、ある日、人々はカニエ・ウェストを忘れてしまったでしょう、そして、彼を指しているすべてのミームはちょうど失礼で少し奇妙になるでしょう。 – RandomInsano

10

あまりにも詳細にすることなく、これは本質的にインスタンス変数のコピーを、すぐに実行する関数にラップして作成し、要素がクリックされたときに実行される関数に戻します。このようなことの

思う:

function() { alert(i); } // Will expose the latest value of i 
(function(I) { return function() { alert(I); }; })(i); // Will pass the current 
                 // value of i and return 
                 // a function that exposes 
                 // i at that time 

だから、ループの各反復の間に、あなたが実際に 実行変数の 現在値で 機能を返す関数です。

あなたが想像ならば、あなたは...

function() { alert(0); }; 
function() { alert(1); }; 
function() { alert(2); }; 
function() { alert(3); }; 

として可視化することができる4つの別々の機能を作成しているあなたのループで4つのアンカーを持っていることを、私はあなたかのようにJavaScriptを使用してスコープとクロージャに探して検討すると、

この道を辿り、予期せぬ行動から何が起こっているのかを正確に理解できない。

onclickイベントがトリガされると、匿名関数が呼び出され、それはループで使用されたのと同じ変数 iを意味し、それはそれが4

を解決する、iの最後の値を保持する

+0

説明をありがとう。それは素敵なハックです - それはjavascriptのやり方ですか? – Amarghosh

2

closureが作成され、あなたがクリックハンドラに機能を割り当てると

a.onclick = (function(k) {return function() { alert(k); }; })(i); 
関連する問題