2009-07-17 2 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 ... 

인해 문제가 참조 루프의 lot_idarea 및 각 반복에서 변경된다는 점이다. 그 결과 모든 요소에 대한 mouseover 이벤트는 lot_id이고 마지막 영역 인 의 영역은입니다.

저는이를 위해 jQuery가 필요하거나 필요하지 않습니다. 글로벌 네임 스페이스를 오염시키지 않는 간단한 JS 솔루션이 선호됩니다. 폐쇄에 루프에 대한 귀하의 내용을 둘러싼

답변

2

시도 :

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

가 그

편집을 어떻게 작동하는지 알려주세요 : 당신은 실제로 전체 루프를 둘러싸 필요가 없습니다, 이벤트를 첨부하는 줄을 둘러 쌀 수 있습니다.

(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를 할당하고 lot_id를 다른 로컬 변수에 저장하고 lotIdForMouseOver를 말한 다음 mouseover 함수에 전달하기 전에 문제를 간단하게 해결할 수 있습니다. 새로운 로컬 변수는 JavaScript가 아닌 C#에서 작동합니다. 직장에서 나는 많은 C#을하고 혼란을 겪습니다!

제안 된 것과 마찬가지로 도우미 기능을 만들어야 좋을 것입니다.

'if'체크를 역으로 사용하면 중첩 된 if를 제거 할 수 있습니다. 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. 
    } 
} 
관련 문제