2011-06-19 20 views
3

ボタンの状態を示すインタラクティブなマップです。各ボタンは、ボタン/状態がクリックされたときに、状態の略語をidとして持っています。私は、関数 "stateSelect"を起動して状態の略語を送信したいと思います私は何が押されたのか知っています。なぜ次のようなことはできませんか?Javascript Array addEventListener

var stateList = new Array("AK","AL","AR","AS","AZ","CA","CO","CT","DC","DE","FL","GA","GU","HI","IA","ID", 
    "IL","IN","KS","KY","LA","MA","MD","ME","MH","MI","MN","MO","MS","MT","NC","ND","NE","NH","NJ","NM","NV","NY", 
    "OH","OK","OR","PA","PR","PW","RI","SC","SD","TN","TX","UT","VA","VI","VT","WA","WI","WV","WY"); 

    for (var i = 0; i < stateList.length; i++) { 
     document.getElementById(stateList[i]).addEventListener('mousedown', function() {stateSelect(stateList[i])}, false); 
    } 

私は明らかに50行のコードを避けたいと思いますが、この単純なループが機能しない理由はわかりません。

答えて

5

ハンドラが実行されると、ループが終了した後のどこであっても、iという値がルックアップされるためです。

あなたが関数内でスコープにi変数が必要になります。

function listenerForI(i) { 
    document.getElementById(stateList[i]).addEventListener('mousedown', function() {stateSelect(stateList[i])}, false); 
} 
for (var i = 0; i < stateList.length; i++) { 
    listenerForI(i); 
} 

今すぐハンドラによって参照iが呼び出されたlistenerForI関数のパラメータとなります。したがって、iは、forループから渡された値を参照します。

+0

私は上記のコードを試してみたところ、アラスカ(AK)のみがクリック可能です。 – Stephen

+0

@Stephen:うまく動作します。 [ここに例があります] – user113716

+0

私はすでにdivを操作して作成したと思っていましたが、その最初のブロックはやりました。とても感謝しています。 – Stephen

1

スコープの問題があります。 JavaScriptはブロックスコープではありません。それは関数スコープです。基本的には、は、ループ内に新しい変数を作成するときはいつでも、新しい関数を作成する必要があります。次のように

そうする最もエレガントな方法は次のとおりです。

stateList.map(function(abbrev){ 
    $(abbrev).mousedown(function(){stateSelect(abbrev)}); 
}); 

あなたはjQueryのを使用していない場合は、単にdocument.getElementById(abbrev).addEventListener$(abbrev).mousedownを交換してください。

(「地図は標準ではありません」と言われている人たちを控除するためだけのもので、すべてのブラウザベンダーのサポートを受けているJavaScript ECMA-262標準第5版です。ちょうど$.map。)

ここでは、ループを使用する方法は、forです。それは少し醜いですが、それは機能を経由して新しいクロージャを作成する必要性を示しています

for(var i=0; i<stateList.length; i++) 
    (function(i){ 
     $(stateList[i]).mousedown(...); 
    })(i); 

私は必要以上に少し醜い、言ったように、あなたはこれもやや醜いですが、基本的に同じことです:

function createListener(abbrev) { 
    $(abbrev).mousedown(...); 
} 
for(var i=0; i<stateList.length; i++) 
    createListener(stateList[i]); 
+0

* "古いブラウザをサポートすることには変態的な人は..." *パラノイアではありません。 IE6-8は 'Array.prototype.map'をサポートしていません。これは巨大な基盤を表しています。 – user113716