尝试将变量传递到foreach循环中的对象的方法构造函数时的范围问题

时间:2012-08-22 17:55:46

标签: javascript jquery

我理解以下代码块中发生了什么,但不确定如何修复它:

for (var i = 0; i < songs.length; i++){
    var listItem = $('<li/>').appendTo(songList);

    var song = songs[i];

    var link = $('<a/>', {
        id: song.id,
        href: '#' + song.id,
        text: song.name,
        contextmenu: function(e){
            var contextMenu = new ContextMenu(song);
            contextMenu.show(e.pageY, e.pageX);

            //Prevent default context menu display.
            return false;
        }
    }).appendTo(listItem);
}

在这种情况下,当在contextmenu方法内部访问时,song将始终是foreach循环中迭代的最后一项。我想知道如何做到这一点,以便链接和他们的定义歌曲之间存在1:1的关系。

我尝试将歌曲对象指定为链接对象的属性(通过this.song访问),但它是未定义的。

2 个答案:

答案 0 :(得分:2)

for (var i = 0; i < songs.length; i++){
    // note this
    (function(i) {
        var listItem = $('<li/>').appendTo(songList);

        var song = songs[i];

        var link = $('<a/>', {
            id: song.id,
            href: '#' + song.id,
            text: song.name,
            contextmenu: function(e){
                var contextMenu = new ContextMenu(song);
                contextMenu.show(e.pageY, e.pageX);

                //Prevent default context menu display.
                return false;
            }
        }).appendTo(listItem);
    // and this
    }(i));
}

请参阅this duplicate以获取解释。

答案 1 :(得分:2)

另一个答案是更好的方法 - 将对象声明为for循环的范围。但是如果声明对象必须在for循环中声明,那么如何解决这个问题:

song在contextMenu函数中声明了一个范围。因此,每当contextMenu执行时,它将查找作用域链直到找到变量,此时它将始终找到最后一个实例化的歌曲。您需要获取contextMenu可用的歌曲副本,这也很棘手,因为对象是通过JavaScript引用传递的。您可以将自调用函数与$ .extend结合使用来复制song(在我的示例中重命名为newSong)并解决此问题:

for (var i = 0; i < songs.length; i++){
    var listItem = $('<li/>').appendTo(songList);

    var song = songs[i];

    var link = $('<a/>', {
        id: song.id,
        href: '#' + song.id,
        text: song.name,
        contextmenu: (function(song){
            var newSong = $.extend(true,{},song);
            return function(e) {
            var contextMenu = new ContextMenu(newSong);
            contextMenu.show(e.pageY, e.pageX);

            //Prevent default context menu display.
            return false;
          };
        })(song);
    }).appendTo(listItem);
}