【问题标题】:Object Modify Problem on Dynamically Created Element EventListener动态创建的元素 EventListener 上的对象修改问题
【发布时间】:2019-10-16 01:29:07
【问题描述】:

我在使用 Vanilla Javascript 对动态创建的元素使用事件侦听器时遇到了一个非常有趣的问题。我先定义问题再贴代码。

我使用 javascript 创建动态 html 元素,并在创建过程中在每个新创建的对象上添加“单击”事件侦听器。在此事件事件侦听器中,我更改了 GLOBAL 对象的不同属性。我的意思是,当您单击动态创建的元素时,每个元素都会修改此全局对象的不同属性。

这里出现问题,我动态选择全局对象的不同属性。因此,对于每个元素,它都会修改全局对象的不同属性。但是当我运行代码时,我看到每个元素只更改全局对象的最新属性。这意味着每个元素都会更改该对象的相同属性,并且它是该对象的最新属性。代码如下:

var filter = {1:false, 4:false, 7:false, 11:false, 8:false} //global object
var productsAndIndexes = {a:1, b:4, c:7, d:11, e:8 } //another global object used for looping 
function createEmptyFilter(){
  var hdr = document.querySelector("div.content .headers");
  for(var product in productsAndIndexes){
    var inp = document.createElement("input");
    inp.setAttribute("type", "checkbox");
    var filterInd = productsAndIndexes[product];

    inp.addEventListener("click" , (e) => {
      if(e.target.checked){
        filters[ filterInd ] = true;
      }else{
        filters[ filterInd ] = false;
      }
    });

    hdr.appendChild(inp);
  }
}
createEmptyFilter();

每次我选中一个复选框时,都会得到 filter = {1:false, 4:false, 7:false, 11:false, 8:true}。但是每个复选框都应该修改其在对象中的相关部分。

感谢任何有关该问题的解释和解决方案(尽管我不是 15 代表 :)) 谢谢

【问题讨论】:

    标签: javascript


    【解决方案1】:

    问题是你的filterInd 变量是用var 声明的,这意味着它是函数作用域,而不是你的for循环块。这意味着每次循环迭代都会覆盖同一个变量,因此点击处理程序都关闭同一个变量,而不是具有不同值的唯一变量。改为使用constlet 声明它,click 处理程序将引用循环迭代的唯一值。

    既然您使用的浏览器足够现代以支持=>,那么您可能支持letconst;现在真的没有充分的理由使用var

    const filter = {1:false, 4:false, 7:false, 11:false, 8:false} //global object
    const productsAndIndexes = {a:1, b:4, c:7, d:11, e:8 } //another global object used for looping 
    function createEmptyFilter(){
      const hdr = document.querySelector("div.content .headers");
      for (let product in productsAndIndexes) {
        const inp = document.createElement("input");
        inp.setAttribute("type", "checkbox");
        const filterInd = productsAndIndexes[product];
    
        inp.addEventListener("click", e => {
          if (e.target.checked) {
            filters[filterInd] = true;
          } else {
            filters[filterInd] = false;
          }
        });
    
        hdr.appendChild(inp);
      }
    }
    createEmptyFilter();
    

    【讨论】:

    • 我差不多明白了,但你说这是因为 var 是函数作用域还是因为“闭包”?由于事件侦听器使用自己的函数,并且由于 fillterInd 处于匿名事件侦听器函数的关闭状态,所以它是作用域的?它使用实际的 filterInd 变量而不是值?但是即使我直接在事件侦听器函数中使用 productsAndIndexes[product],我也得到了相同的结果。虽然 productsAndIndexes 是一个 GLOBAL 变量,但它给出的结果与我使用函数变量的结果相同?
    • 这是因为它们是函数范围的并且闭包引用了该函数范围的变量。根据您的尝试,product 也是函数作用域,因此随着循环的进行,下一个迭代值将分配给相同的 product 变量。因此,当点击处理程序运行时,它们会引用最近分配的值(循环中的最后一个值)。
    • 这也是为什么使用像Object.keys(productsAndIndexes).forEach(product => { /*...*/ }); 这样的东西可以方便地替代循环的原因,因为在forEach 回调中,product 是它自己的独立变量,所以其中的任何内联函数将关闭不同的 product 值。
    • 非常感谢,我现在完全明白了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-18
    • 1970-01-01
    • 2020-02-18
    • 1970-01-01
    • 2014-07-16
    • 2011-03-23
    • 2020-12-09
    相关资源
    最近更新 更多