Javascript 关闭问题。有什么建议吗?

Javascript 关闭问题。有什么建议吗?,javascript,for-loop,closures,Javascript,For Loop,Closures,我对下面与闭包相关的代码有一个问题,我需要一些帮助 正如您所看到的,我在for循环中创建了多个图像,并分配了不同的id(即数组中的数字)。到目前为止,一切顺利。当我单击不同的图像时,我希望使用图像id作为参数调用函数showId,但问题是,作为函数参数使用的数字总是变为nr 8(数组中的最后一个数字)。我怎样才能解决这个问题 提前谢谢 var imageArea = document.getElementById('imageArea'); var nrArray = [1,2,3,4,5,6,

我对下面与闭包相关的代码有一个问题,我需要一些帮助

正如您所看到的,我在for循环中创建了多个图像,并分配了不同的id(即数组中的数字)。到目前为止,一切顺利。当我单击不同的图像时,我希望使用图像id作为参数调用函数showId,但问题是,作为函数参数使用的数字总是变为nr 8(数组中的最后一个数字)。我怎样才能解决这个问题

提前谢谢

var imageArea = document.getElementById('imageArea');
var nrArray = [1,2,3,4,5,6,7,8];

for (var i = 0; i < nrArray.length; i++){
    var image = document.createElement('img');
    image.src = "images/theimage.png";
    image.id = nrArray[i];
    imgArea.appendChild(image);
    image.addEventListener ('click',function() {showId(image.id);},false);
}
var-imageArea=document.getElementById('imageArea');
var-nrray=[1,2,3,4,5,6,7,8];
对于(var i=0;i
只需使用
this
关键字引用父对象即可访问ID:

//In this case, this refers to the object that owns the function, i.e., your img
image.addEventListener ('click',function() {showId(this.id);},false);

为什么不直接使用
这个

var imgArea = document.getElementById('imageArea');
var nrArray = [1,2,3,4,5,6,7,8];

for (var i = 0; i < nrArray.length; i++) {
    var image = document.createElement('img');
    image.src = "images/theimage.png";
    image.id = nrArray[i];
    imgArea.appendChild(image);
    image.addEventListener('click', function() {
        showId(this.id);
    }, false);
}

jsiddle演示:

詹姆斯·希尔的回答指出了摆脱这种情况的简单方法,但当然,您仍然有一个关闭问题。一旦要在事件侦听器中使用的数据不能作为环境的一部分使用(例如,作为
this
的属性),您将再次遇到同样的问题

要解决这个问题,您需要创建一个新的闭包(即
函数
):


在stackoverflow上,对于这个完全相同的问题,有无数个答案,我将在一分钟内找到一些答案,但以下是关键点:

  • Javascript具有词法作用域(非动态作用域)
  • Javascript中最小的Javascript作用域是
    函数
  • 块没有自己的范围
  • Javascript使用变量提升,这意味着在作用域执行并移动到作用域的开头之前找到作用域中的所有变量。这意味着,
    var image=…
    并不是你想象的那样。只有一个
    image
    变量,它(由于词法范围)是您在闭包中访问的变量,在循环结束时,它显然会指向最后一个迭代项
  • 函数是一级对象,这意味着它们被视为变量,可以被分配和传递
  • 通过创建一个自动执行的匿名函数,可以为变量创建一个稳定的作用域
例如:

(function(localImage) {
    image.addEventListener ('click',function() {showId(localImage.id);},false);
})(image);
另外,正如其他人所指出的,事件侦听器闭包是在它们被绑定的上下文中执行的。因此,反过来说,不用担心使用关闭来修复范围,您可以:

image.addEventListener ('click',function() {showId(this.id);},false);
编辑

一些类似问题的链接和关于答案的一些不同观点:


我可以继续说下去,但千万是一个大数字…

一旦代码超出范围,Javascript不会自动从内存中删除变量。这意味着,即使在特定范围内声明变量,在for循环中,在此范围外变量仍然存在

附加到所有映像的事件侦听器正在执行行
$showId(image.id)
但是,由于变量未从内存中删除,因此变量
image
仍然存在,即for循环中的最后一个变量。这就是为什么总是从数组中获取最后一个数字:8

调用eventlistener时,它将变量
this
设置为自己的元素,因此将变量从image更改为this将解决问题。 addEventListener调用变为:


image.addEventListener('click',function(){showId(image.id);},false)

我想知道如果你把image.addEventListener放在imgArea.appendChild上面会发生什么。有时候这比你想象的要容易。谢谢:-)@JasonCraig,不用担心-你基本上就在那里!
image.addEventListener ('click', function (id) {
 return function() { showId(id); };
}(image.id), false);
(function(localImage) {
    image.addEventListener ('click',function() {showId(localImage.id);},false);
})(image);
image.addEventListener ('click',function() {showId(this.id);},false);