2009-07-17 13 views
3

私はいくつかの動作を要素に追加するためにonloadを実行するセットアップ関数を持っています。 setup関数はmouseoverイベントに引数を渡しますが、それらの引数はローカル参照であるためforループ中に変更されています。匿名関数を使用してマウスオーバーを割り当てる際にローカル変数を渡す方法は?

function setupAreas(image, map, lots) { 
    // obj is a simple wrapper for doc.getElementById 
    var image = obj(image); // image for imagemap 
    var map = obj(map); // imagemap element 

    var areas = map.getElementsByTagName('area'); 
    for (var i in areas) { 
     var area = areas[i]; // imagemap area element 
     area.id = area.alt; 
    } 

    for (var lot_id in lots) { 
     if (lot_id != 'Lot No' && lot_id != '') { 
      var area = document.getElementById(lot_id); 
      if (!area || !area.coords) { 
       alert('no map coords for lot '+lot_id); 
      } else { 
       var coords = area.coords.split(","); 
       //alert('tag: '+area.tagName+' id: '+lot_id+' area: '+area); 
       var details = lots[lot_id]; 
       if (details) { 
        // setup mouseover call with complete details of area 
        area.onmouseover = function(){ showLot(lot_id, area, coords, details, image, map, areas, lots) }; 
... snip ... 

問題は、参照forループのlot_idareaが各反復で変更されることです。結果は、任意の要素のmouseoverイベントは、lot_id最後の領域の領域にのみを与えます。

私はこのためにjQueryを必要としたくありません。グローバルな名前空間を汚染しないシンプルなJSソリューションが好まれます。閉鎖であなたのforループの内容を取り巻く

答えて

2

試してみてください。

for (var lot_id in lots) { 
    (function(lid){ 
     //contents of for loop - use lid instead of lot_id  
    })(lot_id); 
} 

私はそれが

EDITうまくいく方法を知ってみましょう:あなたが実際にループ全体を包囲する必要はありませんが、イベントを結んでいる行を囲むことができます:

(function(lid){ 
    area.onmouseover = function(){ showLot(lid, area, coords, details, image, map, areas, lots) }; 
})(lot_id); 

しかし、ループ全体を囲むことで将来のバグを防ぐことができます発生する:)

+1

驚くべきことに、私はJSを何年も使っていて、閉鎖については全く知らなかった。 – SpliFF

2

関数の周りにクロージャを作成する必要があります。この役立つかもしれないような何か:

function makeShowLot(lot_id, area, coords, details, image, map, areas, lots) { 
    return function() { 
     showLot(lot_id, area, coords, details, image, map, areas, lots); 
    }; 
} 

はその後、代わりにこれを行う:

area.onmouseover = makeShowLot(lot_id, area, coords, details, image, map, areas, lots); 

makeShowLotは、関数を返す関数です。返される関数には引数はありません。 showLotに必要なすべての引数は、この無名関数で囲まれています。

0

閉鎖のため正しく表示されているので、 'lot_id'がキャプチャされ、すべてのマウスオーバーイベントで同じです。 onmouseoverを割り当てる前に、問題を解決するのは簡単です。たとえば、lotIdForMouseOverという別のローカル変数にlot_idを格納し、それをmouseover関数に渡します。 新しいローカル変数はJavaScriptではなくC#で動作します。職場では、私はC#の多くをやるので混乱します!

pkaedingのように、ヘルパー関数を作成してください。

「if」チェックを逆にした場合、ネストされたifsを取り除くことができます。 IMHO、フォローするのが非常に難しい場合は入れ子にします。

これはどのように行うのですか。

function setupAreas(image, map, lots) 
{ 
    // existing code 

    for(var lot_id in lots) 
    { 
     if(lot_id == 'Lot No' || lot_id == '') 
      continue; 

     var area = document.getElementById(lot_id); 

     if(!area || ! area.coords) 
     { 
      alert('no maps for coords for lot ' + lot_id); 
      continue; 
     } 

     var coords = area.coords.split(","); 
     var details = lots[lot_id]; 

     if(! details) 
      continue; 

     //makeMouseOver function takes 'n' arguments and returns a function which 
     //will call showLot with those same 'n' arguments. 

     //This is the same suggestion as pkaeding, only that I have exploited 'arguments' 
     //property to make it simpler. 
     var makeMouseOver = function() 
     { 
      var creationArgs = arguments; 
      return function() { showLot.apply(null, creationArgs); }; 
     } 

     area.onmouseover = makeMouseOver(lot_id, area, coords, details, image, map, area, lots); 

     // more code. 
    } 
} 
関連する問題