photo = photos[i]
これを行うと(質問で省略したものがあると仮定して):
img.onclick = function() { window.location = 'pics/user/' + photo.user_id };
関数内の変数photo
は、関数外と同じ変数を参照しphoto
ます。関数を定義した時点で変数の現在の値を取得するのはスナップショットではありません。これは、同じ変数への単なる参照です。周囲のループは、反復ごとにその変数の値を変更しますが、毎回新しい変数を作成するわけではありません。同じものを再利用しています。したがって、生成するすべての関数は、まったく同じ変数 (唯一無二) を参照しますphoto
。
誰かが実際に画像をクリックして関数を呼び出すまでに、ループは終了してからずっと経過photo
しており、メイン プログラムのスコープからは外れていますが、これらのすべての関数がまだループを参照しているため、ループはまだメモリ内にあります。そして、それが最後に割り当てられたものであるため、リストの最後の項目を指していることに気付くでしょう。
したがって、関数が作成されると変更されない独自の変数を各 onclick 関数に与える必要があります。Javascript でこれを行う方法は、ブロック スコープがないため、関数を呼び出して値をパラメーターとして渡すことです。関数内で宣言された関数パラメーターと変数 (関数内で使用されているが関数外で宣言photo
されている上記の動作しない例とは対照的に) は、関数呼び出しごとに新しく作成されます。が関数パラメーターとして宣言されている場合、各 onclick は独自のコピーを取得し、それ以外には何も変更できないため、誰かが最終的に画像をクリックしたときに正しい値が保持されます。photo
静的関数ジェネレーター関数を使用した場合は、より明確になる可能性があります。インラインで宣言して呼び出すことを行う理由はまったくありません。ループの外側で、これを一度宣言できます。
function makeOnclick(somePhoto) {
return function() { hotlink(somePhoto); }
}
そして、ループ本体はこれを行うことができます:
img.onclick = makeOnclick(photo)
それを呼び出してパラメーターとしてmakeOnclick
渡します。関数は遠く離れた場所で宣言されており、直接使用したくても使用できませphoto
ん。その変数はまったく見えません。代わりに、ローカル パラメータだけがあり、これは を呼び出すたびに新しい変数として作成されます。呼び出しの時点での値で初期化されますが、これは単なるコピーであるため、次のループ反復で変更されても、 の特定のインスタンスは同じままです。次の反復で が呼び出されると、 の新しい値に初期化された の新しいインスタンスが作成され、以降も同様です。したがって、返される内部関数が継承されているにもかかわらず、makeOnclick
photo
somePhoto
makeOnclick
photo
photo
somePhoto
makeOnclick
somePhoto
photo
makeOnClick
somePhoto
var、その var はmakeOnClick
;のインスタンス用に特別に作成されたものです。これらの返された関数はすべて、独自の private を取得しsomePhoto
ます。
上記の作業コードは、わずかに異なる方法でまったく同じことを行っています。ループの外側で関数を一度宣言して何度も呼び出す代わりにmakeOnclick
、ループを介して毎回匿名関数として再宣言し、すぐに呼び出します。このコード:
img.onclick = (function(x) { blah(x); })(photo);
これと同じです:
function foo(x) { blah(x); }
img.onclick = foo(photo);
関数に名前を付ける必要はありません。一般的な JavaScript では、次のようになります。
(function (x,y,z) { doSomething(x,y,z); })(a,b,c);
これと同じです:
function callDoSomething(x,y,z) { doSomething(x,y,z); }
callDoSomething(a,b,c);
ただし、関数には名前がなく、どこにも保存されません。呼び出された直後に消えます。
そのため、ループを通過するたびに onclick-generator 関数を宣言し、すぐに一度に呼び出すのは適切で簡潔ですが、それほど効率的ではありません。