Javascript 尝试在foreach循环中将变量传递到对象的方法构造函数时出现范围问题
我理解以下代码块中发生的情况,但不确定如何修复:Javascript 尝试在foreach循环中将变量传递到对象的方法构造函数时出现范围问题,javascript,jquery,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: so
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的关系
我尝试将song对象指定为通过this.song访问的链接对象的属性,但结果显示为未定义
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));
}
请参阅以获取解释
请参阅以获取解释。另一个答案是将对象声明在for循环范围之外的更好方法。但是,如果必须在for循环中声明对象,下面介绍如何解决这个问题: 歌曲从contextMenu函数向上声明一级范围。因此,每当contextMenu执行时,它都会查找范围链,直到找到变量为止,在这个点上它将始终找到最后一首实例化的歌曲。您需要在contextMenu中获得歌曲的副本,这也很棘手,因为对象在JavaScript中是通过引用传递的。您可以将自调用函数与$.extend结合使用,以复制我的示例中重命名为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);
}
另一个答案是更好的方法,将对象声明在for循环的范围之外。但是,如果必须在for循环中声明对象,下面介绍如何解决这个问题: 歌曲从contextMenu函数向上声明一级范围。因此,每当contextMenu执行时,它都会查找范围链,直到找到变量为止,在这个点上它将始终找到最后一首实例化的歌曲。您需要在contextMenu中获得歌曲的副本,这也很棘手,因为对象在JavaScript中是通过引用传递的。您可以将自调用函数与$.extend结合使用,以复制我的示例中重命名为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);
}
可能是重复的啊。你是对的,这是一个副本。不过,我在将逻辑扩展到我的应用程序时遇到了一些问题。我会摆弄它,如果我一分钟内弄明白了,我就把它关上!可能是重复的啊。你是对的,这是一个副本。不过,我在将逻辑扩展到我的应用程序时遇到了一些问题。我会摆弄它,如果我一分钟内弄明白了,我就把它关上!谢谢你。显然,闭包对我来说还是有点奇怪干杯,谢谢你。显然,闭包对我来说还是有点奇怪干杯。你的回答似乎同样有效,但我想我更喜欢用闭包的形式包装,而不是用这种方式创建副本。我想这只是个人偏好。我们的答案都使用闭包,但我只是想展示一个方法,如果引用范围外对象是一个需要$.extend的需求,那么您可以在其中解决这个问题。当然,在你的案例中,他的答案是更好的方法。你的答案似乎同样有效,但我认为我更喜欢用闭包的形式包装,而不是用这种方式创建副本。我想这只是个人偏好。我们的答案都使用闭包,但我只是想展示一个方法,如果引用范围外对象是一个需要$.extend的需求,那么您可以在其中解决这个问题。不过,可以肯定的是,他的答案是你最好的方法。