以下は、私が実行しようとしているものの簡易版です。
for (var i = 0; i < results.length; i++) {
marker = results[i];
google.maps.event.addListener(marker, 'click', function() {
change_selection(i);
});
}
しかし、すべてのリスナーがresults.lengthの値(forループが終了するときの値)を使用していることがわかりました。リスナーを追加して、それぞれがiへの参照ではなく、追加するときにiの値を使用するようにするにはどうすればよいですか?
最新のブラウザでは、let
またはconst
キーワードを使用して、ブロックスコープの変数を作成できます。
for (let i = 0; i < results.length; i++) {
let marker = results[i];
google.maps.event.addListener(marker, 'click', () => change_selection(i));
}
古いブラウザーでは、関数パラメーターとして変数を渡すことにより、変数を現在の状態で保存する別のスコープを作成する必要があります。
for (var i = 0; i < results.length; i++) {
(function (i) {
marker = results[i];
google.maps.event.addListener(marker, 'click', function() {
change_selection(i);
});
})(i);
}
無名関数を作成し、変数を最初の引数として呼び出して、関数に値を渡し、クロージャーを作成します。
クロージャーと同様に、function.bind
:
google.maps.event.addListener(marker, 'click', change_selection.bind(null, i));
i
の値を呼び出し時に関数の引数として渡します。 (null
はthis
をバインドするためのもので、この場合は必要ありません。)
function.bind
は、Prototypeフレームワークによって導入され、ECMAScript Fifth Editionで標準化されました。ブラウザがすべてネイティブにサポートするまで、独自のfunction.bind
クロージャの使用をサポート:
if (!('bind' in Function.prototype)) {
Function.prototype.bind= function(owner) {
var that= this;
var args= Array.prototype.slice.call(arguments, 1);
return function() {
return that.apply(owner,
args.length===0? arguments : arguments.length===0? args :
args.concat(Array.prototype.slice.call(arguments, 0))
);
};
};
}
閉鎖:
for (var i = 0, l= results.length; i < l; i++) {
marker = results[i];
(function(index){
google.maps.event.addListener(marker, 'click', function() {
change_selection(index);
});
})(i);
}
EDIT、2013:これらは現在、一般的に [〜#〜] iife [〜#〜] と呼ばれています
あなたはクロージャで終了しています。 これはクロージャに関する記事です とそれらの操作方法。ページの例5をご覧ください。それがあなたが扱っているシナリオです。
編集:4年後、そのリンクは死んでいます。上記の問題の根本は、for
ループがクロージャーを形成することです(具体的にはmarker = results[i]
)。 marker
がaddEventListener
に渡されると、クロージャーの副作用がわかります。共有の「環境」は、ループの各反復で更新され、その後クロージャーを介して最終的に「保存」されます最後の繰り返し。 MDNはこれを非常によく説明します。