如何将变量的当前值传递给事件处理程序 (Javascript)

How can I pass the current value of a variable to an event handler (Javascript)

对此有点尴尬,但可以说我在一个名为 iBlock 的 parent 元素中有这组 'child' 元素,并且在一个函数中我添加了一个 'onclick' 事件到每个 child,像这样...

someFunction(iBlock) {
    var el, iTotal = iBlock.children.length;
     for (var i= 0; i < iTotal; i++) {
             el=iBlock.children[i];
             el.onclick=function(event){myHandler(this, i)};
             }
    }

所以给定一个这样的 onclick 处理程序...

function myHandler(elem, n) {
     alert("number is: " +  n);
    }

有点意外的是,无论我点击哪个child元素,这个例子中的处理程序总是显示小于children总数的那个。但我知道 total - 1 是变量 'i' 在循环结束之前达到的最高数字,并且处理程序除了事件发生时的变量值外不会传递任何东西。但是理解这并不能帮助我回答这两个问题...

  1. 如果我真的想让 onclick 函数中的第二个参数 传递 值 'i' 实际上是 在 onclick 处理程序是 附加 ,我可以传递什么来代替原始 'i' 变量?
  2. 由于 'i' 是由函数中的 'var' 关键字声明的 添加了处理程序,为什么它仍然有一个值(在这种情况下 总 - 1),安装功能恢复后?如果处理程序显示 'undefined',我就不会那么惊讶了。我意识到 这是一个 'scope of variables' 问题,但我确定它是相关的。

关于第一个问题,我试过传递:i+'x',只是为了把它变成一个字符串,希望它能生成一个唯一的实例。这也不起作用...并且元素 'clicked' on 只会触发显示“4x”的处理程序。我还尝试创建第二个变量,作为一个字符串,然后提取数字部分,并将最终的 'value' 从新变量传递给 onclick 处理程序,就像这样...

someFunction(iBlock) {
        var el, iTotal = iBlock.children.length;
         for (var i= 0; i < iTotal; i++) {
            el=iBlock.children[i];
            var n= i+'x';  // make 'i' into a new longer string variable
            var r = /\d+/;    // regex, to capturei digits
            n = n.match(r); // convert the string to only contain the digits
            el.onclick=function(event){myHandler(this, n)};
            }
        }

没有变化。处理程序仍然在我单击的任何元素上显示总计 1。

我看过关于这个主题的类似帖子,例如 Extract a number from a string (JavaScript),但我仍然不明白第一个问题的补救方法。

PS(我没有尝试使用 'let' 而不是 'var' 创建变量,因为我非常致力于支持某些较旧的浏览器)。 编辑:如果可能的话,我想在 'old browsers' 中包括 IE-8。我知道我不能总是这样做,但在这种情况下我想这样做。

编辑:我发现了一个有趣的解决方法,即在我添加处理程序的循环中将我自己的变量添加到每个元素,就像这样...

someFunction(iBlock) {
    var el, iTotal = iBlock.children.length;
     for (var i= 0; i < iTotal; i++) {
             el=iBlock.children[i];
             el.onclick=function(event){myHandler(this, i)};
             el.myIndex=i;
             }
    }

然后当然在我的处理程序中,无论如何我都会传递 'this',我可以通过检查 'this.myIndex 正确地恢复 'i' 的期望值。我听说这很危险,因为它可能与未来发生冲突 DOM 属性.

但这似乎 'kludge',所以我仍然对答案感兴趣!

el 没有分配给任何东西。尝试:

someFunction(iBlock) {
    var iTotal = iBlock.children.length;
    for (var i= 0; i < iTotal; i++) {
        iBlock.children[i].onclick=function(event){myHandler(this, i)};
    }
}

您需要使用 IIFE 创建一个闭包来捕获迭代器变量。

More about closures

More about IIFE

function handleClick(element, n) {
    alert("number is: " +  n);
}

function iterateOverChildNOde(parentNode) {
  var el = parentNode.children
  var iTotal = parentNode.children.length;
 
  
    for (var i= 0; i < iTotal; i++) {

    (function(iterator){
      el[i].onclick=function(event){handleClick(el[iterator], iterator)};
      })(i)
  }
}

iterateOverChildNOde(document.getElementById('parent'));
<div id="parent">
  <div class="child">C</div>
  <div class="child">L</div>
  <div class="child">I</div>
  <div class="child">I</div>
  <div class="child">C</div>
  <div class="child">L</div>
</div>

此外,您需要意识到这是一种不好的做法。您应该只将事件处理程序附加到父元素,然后使用 e.target.

More about event delegation

  function handleClick(element, n) {
        alert("number is: " +  n);
    }

document.getElementById('parent').onclick=function(e){handleClick(e.target, Array.prototype.indexOf.call(this.children, e.target))}
    <div id="parent">
      <div class="child">C</div>
      <div class="child">L</div>
      <div class="child">I</div>
      <div class="child">I</div>
      <div class="child">C</div>
      <div class="child">L</div>
    </div>

如评论中所述,问题在于您的内联点击处理函数在闭包中引用了变量 i,该变量在循环时发生了变异。每个处理程序都引用该循环变量,因此在循环结束时,i 设置为 iTotal,并且所有处理程序都引用相同的值。

这可能是使用函数的 bind 方法的好时机。它所做的是 return 一个新版本的函数,其中建立了 this 上下文和参数 pre-populated.

for (var i = 0; i < iTotal; i++) {
  el = iBlock.children[i];
  el.addEventListener('click', myHandler.bind(this, this, i));
}

每个 el 接收一个具有前两个参数的唯一函数 pre-populated。

在仔细考虑所有提供的答案后,我将在我的 OP 的最终编辑中坚持使用我发现并发布的解决方案。具体来说,它在我添加事件时为每个元素分配一个新属性...

someFunction(iBlock) {
    var el, iTotal = iBlock.children.length;
     for (var i= 0; i < iTotal; i++) {
             el=iBlock.children[i];
             el.onclick=function(event){myHandler(this)};
             el.myIndex=i;
             }
    }

在这里,由于注意到的问题,我什至不再尝试将 'i' 的值作为第二个 arg 发送到处理程序。然而,无论出于何种原因,当添加的元素 'myIndex' 被分配给 'i' 时,它会保留分配时的标识值。因此,当调用处理程序时,可以通过 'this.myIndex' 访问它。我不完全理解为什么这样做会导致 'i' 按值传递而不是引用/实例本身,但它有效。

没有人提出不这样做的任何理由,就添加的代码而言,它似乎是最不复杂的。我认为唯一的风险是选择一个与将来的 'standard' 属性冲突的名称。也许这就是为什么我看到建议 tp call add on sttributes something like "data-myindex"。但无论哪种方式,它似乎都适用于我尝试过的所有 IE 平台,包括 IE8、Edge、Chrome 和 Firefox,以及通过 Win-10 上的最新版本为 Windows-XP 分发的最后一个平台。它适用于 IOS-7 之前的 Mobil Safari,以及我能够测试的所有 android 设备。仍然对建议持开放态度,但有时,正如他们所说,“最简单的解决方案是最好的”