对于带有JavaScript对象的循环

对于带有JavaScript对象的循环,javascript,loops,object,addeventlistener,Javascript,Loops,Object,Addeventlistener,我现在在JavaScript的循环方面遇到了问题。我有一个目标: var object = { objectInObject: { name: "Banana" }, objectInObject2: { name: "Apple" }, objectInObject3: { name: "Carrot" } } 我在对象的对象中循环: for(var key in object){ var

我现在在JavaScript的循环方面遇到了问题。我有一个目标:

var object = {
    objectInObject: {
        name: "Banana"
    },
    objectInObject2: {
        name: "Apple"
    },
    objectInObject3: {
        name: "Carrot"
    }
}
我在对象的对象中循环:

for(var key in object){
    var li = document.createElement('li');
    li.textContent = object[key].name;
    ul.appendChild(li);
    li.addEventListener('click', function(){
        console.log(object[key]);
    })
}

我遇到的问题是,当我添加一个事件侦听器并单击列表项(例如“香蕉”)时,当I console.log它仍然显示“Carrot”。因此,无论我单击哪个列表项,它都只显示最新的列表项。我不知道为什么会这样。任何帮助都将不胜感激

之所以发生这种情况,是因为“key”周围有一个闭包。分配给正在生成的三个元素的事件处理程序都共享父函数中的“key”变量。“key”得到的最后一个值是Carrot,因此这是所有处理程序共享的值

将“var key”更改为“let key”,为“key”创建块作用域并避免闭包。此更改允许“键”在每次循环迭代时都是全新的,因此每个事件处理程序不会与其他任何事件处理程序共享“键”

有关闭包的更多信息,请访问:

另外,仅供参考,将变量命名为“object”不是一个好主意,因为这可能与“object”类型冲突


最后,在循环中修改DOM从来都不是一个好主意。相反,构建一个documentFragment,然后在循环完成时只追加一次。

for(var key in object)
更改为
for(let key in object)
这里需要注意两件事

首先,使用对象的hasOwnProperty()方法来确保您访问的是该对象上的键,而不是原型链上更高的任何东西,这是一个很好的实践。像这样:

for(var key in object){
    if (object.hasOwnProperty(key) {
        // do whatever you need with object[key] here safely
    }       
}
第二,你之所以得到所有这些的Carrot,是因为当你遍历对象时key的值“没有被保存”。真正发生的是在偶数侦听器回调中,保存了对键的引用。当您遍历所有对象时,到达的最后一个关键点将成为所有事件侦听器指向的同一个关键点

您所需要的可以通过引入闭包来完成,或者更具体地说,通过创建新的执行环境来完成。最简单的方法可能是立即调用函数表达式(IIFE):


这里发生的事情是,通过创建新的函数作用域,键不再被所有事件侦听器回调引用。它们都创建并立即执行一个新函数,每个函数都有自己的作用域,并有自己的“key”值,您只需传入即可。

我就是这样做的

var对象={
目标对象:{
名称:“香蕉”
},
目标2:{
名称:“苹果”
},
目标项目3:{
名称:“胡萝卜”
}
}
var ul=document.getElementById(“容器”);
for(对象中的变量键){
var li=document.createElement('li');
li.textContent=对象[key]。名称;
li.setAttribute(“数据id”,对象[key].name);
li.addEventListener('click',function()){
log(this.getAttribute(“数据id”);
});
ul.儿童(li);
}
li:悬停{
光标:指针;
}

    它可能会重复工作!!!但我不完全确定为什么。我认为‘var’和‘let’在本例中是相同的,因为它们都在‘for’范围内?也许再解释一点,因为我不太明白。非常感谢您提供的提示。实际上没有。var没有给您范围。var在这里为您提供了函数范围,这就是问题的原因。我们也不给你范围。它为for的每个迭代提供了一个新的范围。
    li.addEventListener('click', function(){
        (function(key) {
            console.log(key);
        })(object[key]);
    })