118

これは、私が実行しようとしているものの簡略化されたバージョンです。

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 の値を使用するようにリスナーを追加するにはどうすればよいですか?

4

6 に答える 6

161

最新のブラウザーでは、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);
}

匿名関数を作成し、変数を最初の引数として呼び出すことで、関数に値渡しを行い、クロージャを作成します。

于 2010-04-02T20:24:28.363 に答える
35

クロージャーと同様に、次のものを使用できますfunction.bind

google.maps.event.addListener(marker, 'click', change_selection.bind(null, i));

関数が呼び出されたときに inの値をi引数として関数に渡します。(nullは binding 用thisで、この場合は必要ありません。)

function.bindPrototype フレームワークによって導入され、ECMAScript 第 5 版で標準化されました。すべてのブラウザーがネイティブにサポートするまでは、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))
            );
        };
    };
}
于 2010-04-02T22:19:35.487 に答える
13

閉鎖:

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);
}

編集、2013: これらは現在、一般的にIIFEと呼ばれています。

于 2010-04-02T20:25:38.370 に答える
2

あなたは閉鎖に巻き込まれています。クロージャーとその使用方法に関する記事を次に示します。ページの例 5 を確認してください。それがあなたが扱っているシナリオです。

編集: 4 年後、そのリンクは死んでいます。上記の問題の根本は、forループがクロージャーを形成することです (特に でmarker = results[i])。markerが に渡されるとaddEventListener、クロージャーの副作用がわかります。共有された「環境」は、ループの反復ごとに更新され、最後の反復の後にクロージャーを介して最終的に「保存」されます。MDN はこれを非常によく説明しています。

于 2010-04-02T20:24:30.233 に答える
-2
for (var i = 0; i < results.length; i++) {
    marker = results[i];
    google.maps.event.addListener(marker, 'click', (function(i) {
        return function(){
            change_selection(i);
        }
    })(i)); 
}
于 2014-05-17T15:45:58.130 に答える
-4

i の値を格納する一時変数を定義できると思います。

for (var i = 0; i < results.length; i++) {
 var marker = results[i];
 var j = i;
 google.maps.event.addListener(marker, 'click', function() { 
   change_selection(j);
 }); 
}

私はそれをテストしていません。

于 2012-06-06T17:20:56.863 に答える