我理解以下代码块中发生了什么,但不确定如何修复它:
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访问),但它是未定义的。
答案 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);
}