javascript - Javascript 中 for 循环内的闭包结果令人困惑

标签 javascript for-loop closures iife

我是 JavaScript 的初学者,我已经阅读了类似主题中的每个答案,但我仍然无法理解到底发生了什么,因为没有人解释我感到困惑的部分。

我有一个包含两个段落的 HTML 文档,这就是我用来将段落颜色更改为 red 的内容。当我点击它时:

var func = function() {
/*Line 1*/ var paragraphs = document.querySelectorAll('p')
/*Line 2*/
/*Line 3*/ for (var i = 0; i < paragraphs.length; i++) {
/*Line 4*/    p = paragraphs[i]
/*Line 5*/    p.addEventListener('click', function() {
/*Line 6*/      p.classList.toggle('red')
/*Line 7*/    })
/*Line 8*/ }
}
func();

结果是,无论我点击哪里,只有最后一段的颜色变为红色。所有与我类似的问题的答案都说在For之后循环结束,i的值将是1 ,这就是闭包将使用的内容,然后是 eventListener将添加到相同的第二段中?我可以使用 Immediately-Invoked Function 修复此问题或let制作i闭包私有(private),我不知道为什么我应该制作 ì如果闭包在循环的每次迭代中都可以访问它,则为私有(private)..

我只是不明白这里到底发生了什么,循环不是一行接一行地执行的吗?一开始i值为 0 ,所以在Line 4变量p将有第一段,然后在 Line 5-6该函数将使用 p并将监听器附加到它,然后第二次执行循环并 i值为 1 ,然后在 Line 5-6闭包再次获得新值 p

我知道闭包可以访问这里的全局变量,例如 i ,因此它可以访问 pLine 4当其值发生变化时。

请问我在这里缺少什么?预先非常感谢您!

最佳答案

您正在展示众所周知的闭包示例......

一开始这可能很难理解

/*Line 1*/ var paragraphs = document.querySelectorAll('p')
/*Line 2*/
/*Line 3*/ for (var i = 0; i < paragraphs.length; i++) {
/*Line 4*/    p = paragraphs[i]
/*Line 5*/    p.addEventListener('click', function() {
/*Line 6*/      p.classList.toggle('red')
/*Line 7*/    })
/*Line 8*/ }

第 5、6 和 7 行包含每个段落中存储的匿名回调函数。该函数依赖于父函数中的变量 i,因为内部函数使用定义为 paragraphs[i]p。因此,即使您没有在内部函数中显式使用 i,您的 p 变量也是如此。假设文档中有 7 个段落...因此,您有 7 个围绕一个 i 变量“封闭”的函数。当父函数终止时,i 不能超出范围,因为 7 个函数需要它。因此,当有人点击其中一个段落时,循环已完成(i 现在将为 8),并且每个函数都会查看相同的 i > 值。

为了解决这个问题,点击回调函数需要各自获取自己的值,而不是共享一个。这可以通过多种方式完成,但它们都涉及将 i 的副本传递到点击回调函数中,以便将 i 值的副本存储在每个点击回调函数或完全删除 i 的使用。仍然会有一个闭包,但不会出现您最初遇到的副作用,因为嵌套函数不会依赖于父函数中的变量。

下面是一个从嵌套函数中删除 i 的示例,从而解决了问题:

var paragraphs = document.querySelectorAll('p')

for (var i = 0; i < paragraphs.length; i++) {
    paragraphs[i].addEventListener('click', function() {
      this.classList.toggle('red')
    });
}
.red {color:red;}
<p>Paragraph</p>
<p>Paragraph</p>
<p>Paragraph</p>
<p class="red">Paragraph</p>
<p>Paragraph</p>
<p>Paragraph</p>

关于javascript - Javascript 中 for 循环内的闭包结果令人困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40389682/

相关文章:

javascript - Bootstrap 可切换选项卡菜单将内容向下推

javascript - 将参数传递到 FOR 循环中

java - 哪一个更快 : an array of x integers or an object containing x integer fields?

javascript - 如何使用事件监听器的构造函数方法

javascript - 按对象值排序不起作用?

javascript - 手机innerWidth,innerHeight vs Resolution

javascript - Javascript 中使用星星的圣诞树

c++ - 尝试在 for 循环中使用 2 个列表迭代器

ios - PromiseKit ios Swift 闭包返回类型问题

python - 了解 Python 闭包