如何通过匿名函数分配鼠标悬停时传递局部变量?

时间:2009-07-17 00:27:05

标签: javascript

我有一个运行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解决方案。

3 个答案:

答案 0 :(得分:2)

尝试在闭包中包含for循环的内容:

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 :(得分: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所需的所有参数都包含在这个匿名函数中。

答案 2 :(得分:0)

正如您因为关闭而正确观察时,捕获了'lot_id',并且对于所有鼠标悬停事件都是相同的。 修复问题很简单,在分配onmouseover之前,将lot_id存储在另一个本地var中,比如lotIdForMouseOver,并将其传递给mouseover函数。新的本地var事物将在C#中工作,而不是在JavaScript中。在工作中,我做了很多C#,因此混乱!

与pkaeding建议一样,创建一个辅助函数,你应该很好。

另一方面,如果你'反''你的'if'检查,你可以摆脱嵌套的ifs。 恕我直言,嵌套如果很难遵循。

这是我将如何做到的。

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.
    }
}