循环中的函数(返回另一个函数)如何工作?

IT技术 javascript loops closures dom-events anonymous-function
2021-02-06 06:22:39

我一直在尝试为onclickJavaScript 中动态创建的“a”标签的事件分配一个函数所有标签都是在循环中创建的,如下所示:

for ( var i = 0; i < 4; i++ )
{
  var a = document.createElement( "a" );
  a.onclick = function( ) { alert( i ) };
  document.getElementById( "foo" ).appendChild( a );
}

所有四个链接的警报值始终为“4”。很明显。在谷歌搜索时,我发现了一个显示以下代码片段的帖子:

a.onclick = (function(p, d) {
return function(){ show_photo(p, d) }
})(path, description);

我设法根据我的需要调整它并使警报( i )正常工作,但如果有人能准确解释上述代码的作用,我将不胜感激。

3个回答

当您将函数分配给单击处理程序时,将创建一个闭包

基本上,当您嵌套函数时会形成一个闭包,即使在其父函数已经执行之后,内部函数也可以引用其外部封闭函数中存在的变量。

在执行 click 事件时,处理程序引用i变量的最后一个值,因为该变量存储在闭包中。

正如您所注意到的,通过包装单击处理程序函数以接受i变量作为参数,并返回另一个函数(基本上是创建另一个闭包),它按您的预期工作:

for ( var i = 0; i < 4; i++ ) {
  var a = document.createElement( "a" );
  a.onclick = (function(j) { // a closure is created
    return function () {
      alert(j); 
    }
  }(i));
  document.getElementById( "foo" ).appendChild( a );
}

当您迭代时,实际上创建了 4 个函数,每个函数i在创建时存储一个引用(通过传递i),这个值存储在外部闭包中,当点击事件触发时执行内部函数。

我使用下面的代码片段来解释闭包(以及curry 的一个非常基本的概念),我认为一个简单的例子可以更容易地理解这个概念:

// a function that generates functions to add two numbers
function addGenerator (x) { // closure that stores the first number
  return function (y){ // make the addition
    return x + y;
  };
}

var plusOne = addGenerator(1), // create two number adding functions
    addFive = addGenerator(5);

alert(addFive(10)); // 15
alert(plusOne(10)); // 11
泰勒,我为你感到高兴,我会让你完成的,但这篇文章是有史以来最好的,有史以来最好的。
2021-03-19 06:22:39
难怪你有 42k 点:)
2021-03-28 06:22:39
总有一天,人们会像我一样忘记 Kanye West,所有提到他的模因都会显得粗鲁和有点奇怪。
2021-04-01 06:22:39

无需过多赘述,这实际上是通过将实例变量包装在一个立即执行的函数中,并将其传递回将在单击元素时执行的函数来创建实例变量的副本。

可以这样想:

function() { alert(i); }  // Will expose the latest value of i
(function(I) { return function() { alert(I); }; })(i); // Will pass the current
                                                       // value of i and return
                                                       // a function that exposes
                                                       // i at that time

因此,在循环的每次迭代期间,您实际上是在执行一个函数,该函数返回一个具有变量当前值的函数

其中,如果您想象您的循环中有 4 个锚点,那么您正在创建 4 个独立的函数,这些函数可以被可视化为..

function() { alert(0); };
function() { alert(1); };
function() { alert(2); };
function() { alert(3); };

我会考虑使用 javascript 研究范围和闭包,就好像您沿着这条路走下去并且不完全了解正在发生的事情,您可能会因意外行为而遇到大量问题。

感谢您的解释。这是一个不错的 hack - 或者它是在 javascript 中完成的方式吗?
2021-04-03 06:22:39

当 onclick 事件被触发时,匿名函数被调用,它引用i循环中使用的同一个变量,它保存 的最后一个值i,即 4。

您的问题的解决方案是使用返回函数的函数:

a.onclick = (function(k) {return function() { alert(k); }; })(i);