web-dev-qa-db-ja.com

JS変数の値(参照ではなく)を関数に渡すにはどうすればよいですか?

以下は、私が実行しようとしているものの簡易版です。

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

115
ryan

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

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

161
Andy E

クロージャーと同様に、function.bind

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

iの値を呼び出し時に関数の引数として渡します。 (nullthisをバインドするためのもので、この場合は必要ありません。)

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

閉鎖:

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 [〜#〜] と呼ばれています

13
David Murdoch

あなたはクロージャで終了しています。 これはクロージャに関する記事です とそれらの操作方法。ページの例5をご覧ください。それがあなたが扱っているシナリオです。

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

2
ajm