【问题标题】:For Loops With Objects JavaScript带有对象 JavaScript 的 For 循环
【发布时间】:2017-05-10 02:22:57
【问题描述】:

我目前在使用 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]);
    })
}

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

【问题讨论】:

标签: javascript loops object addeventlistener


【解决方案1】:

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

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

您可以阅读更多关于闭包的信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures

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

最后,在循环中修改 DOM 绝不是一个好主意。而是构建一个 documentFragment,然后在循环结束时仅附加一次。

【讨论】:

  • 嘿,成功了!!!但我不完全确定为什么。我认为在这种情况下'var'和'let'会是相同的,因为它们都在'for'范围内?也许再解释一下,因为我不太明白。非常感谢您的提示。
  • 其实没有。 var 不给你范围。 var 在这里为您提供函数范围,这就是导致问题的原因。 let 实际上也没有给你范围。它为 for 的每次迭代提供了一个新的范围。
【解决方案2】:

for(var key in object) 更改为for(let key in object)

【讨论】:

    【解决方案3】:

    这里有两点需要注意。

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

    for(var key in object){
        if (object.hasOwnProperty(key) {
            // do whatever you need with object[key] here safely
        }       
    }
    

    其次,您为所有这些都获得 Carrot 的原因是,当您遍历对象时,键的值“没有被保存”。真正发生的是在您的监听器回调中,正在保存对密钥的引用。当您遍历所有对象时,到达的最后一个键与所有事件侦听器指向的键相同。

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

    li.addEventListener('click', function(){
        (function(key) {
            console.log(key);
        })(object[key]);
    })
    

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

    【讨论】:

      【解决方案4】:

      我会这样做。

      var object = {
          objectInObject: {
              name: "Banana"
          },
          objectInObject2: {
              name: "Apple"
          },
          objectInObject3: {
              name: "Carrot"
          }
      }
      
      var ul = document.getElementById("container");
      for(var key in object){
      
          var li = document.createElement('li');
          
          li.textContent = object[key].name;
          li.setAttribute("data-id", object[key].name);
          
          li.addEventListener('click', function(){
              console.log(this.getAttribute("data-id"));
          });
          
          ul.appendChild(li);
          
      }
      li:hover {
        cursor: pointer;
      }
      <ul id='container'></ul>

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-11-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多