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

时间:2021-02-13 20:57:13

This question already has an answer here:

这个问题已经有了答案:

I've been trying to assign a function to onclick event of a dynamically created "a" tag in JavaScript. All of the tags are created in a loop as follows:

我一直在尝试为JavaScript中动态创建的“a”标记的onclick事件分配一个函数。所有标签在循环中创建如下:

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

The alerted value for all four links is always "4". Pretty obvious. When googling I came across a post that shows the following code snippet:

所有四个链接的警报值总是“4”。显而易见的。当我在google上搜索的时候,我发现了一个显示如下代码片段的帖子:

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

I managed to tweak it for my needs and got the alert( i ) thing to work correctly but I'll appreciate if someone could explain exactly what the above code does.

我设法调整了它以满足我的需要,并使警报(I)工作正确,但是如果有人能确切地解释上面的代码是做什么的,我会很感激。

3 个解决方案

#1


45  

When you assign the function to the click handler, a closure is created.

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

Basically a closure is formed when you nest functions, inner functions can refer to the variables present in their outer enclosing functions even after their parent functions have already executed.

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

At the time that the click event is executed, the handler refers to the last value that the i variable had, because that variable is stored on the closure.

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

As you noticed, by wrapping the click handler function in order to accept the i variable as an argument, and returning another function (basically create another closure) it works as you expect:

正如您所注意到的,通过包装click handler函数以接受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 );
}

When you iterate, actually create 4 functions, each function store a reference to i at the time it was created (by passing i), this value is stored on the outer closure and the inner function is executed when the click event fires.

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

I use the following snippet to explain closures (and a very basic concept of curry), I think that a simple example can make easier to get the concept:

我使用下面的代码片段来解释闭包(以及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

#2


10  

Without going into too much detail this essentially creates copies of the instance variables by wrapping them in a function that executes immediately and passes the back to the function that will be executed when the element gets clicked.

无需过多详细说明,它通过将实例变量包装在一个函数中来创建实例变量的副本,该函数立即执行,并将返回值传递给在单击元素时将执行的函数。

Think of it like this:

这样想:

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

So during each iteration of the loop you are actually executing a function that returns a function with the current value of the variable.

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

Which, if you imagine that you have 4 anchors in your loop you are creating 4 separate functions that can be visualized as..

如果你想象你的循环中有4个锚你就会创建4个独立的函数可以被想象成。

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

I would consider looking into scope and closures with javascript as if you go down this road and don't understand exactly what is happening you can run into massive problems from unexpected behavior.

我将考虑使用javascript来研究范围和闭包,就好像沿着这条路走下去,不知道到底发生了什么一样,您可能会因为意外的行为而遇到巨大的问题。

#3


2  

When the onclick event is triggered, the anonymous function is called and it refers to the same variable i that was used in the loop and it holds the last value of i, that is 4.

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

The solution to your problem is to use a function returning a function:

解决您的问题的方法是使用函数返回一个函数:

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

#1


45  

When you assign the function to the click handler, a closure is created.

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

Basically a closure is formed when you nest functions, inner functions can refer to the variables present in their outer enclosing functions even after their parent functions have already executed.

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

At the time that the click event is executed, the handler refers to the last value that the i variable had, because that variable is stored on the closure.

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

As you noticed, by wrapping the click handler function in order to accept the i variable as an argument, and returning another function (basically create another closure) it works as you expect:

正如您所注意到的,通过包装click handler函数以接受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 );
}

When you iterate, actually create 4 functions, each function store a reference to i at the time it was created (by passing i), this value is stored on the outer closure and the inner function is executed when the click event fires.

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

I use the following snippet to explain closures (and a very basic concept of curry), I think that a simple example can make easier to get the concept:

我使用下面的代码片段来解释闭包(以及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

#2


10  

Without going into too much detail this essentially creates copies of the instance variables by wrapping them in a function that executes immediately and passes the back to the function that will be executed when the element gets clicked.

无需过多详细说明,它通过将实例变量包装在一个函数中来创建实例变量的副本,该函数立即执行,并将返回值传递给在单击元素时将执行的函数。

Think of it like this:

这样想:

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

So during each iteration of the loop you are actually executing a function that returns a function with the current value of the variable.

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

Which, if you imagine that you have 4 anchors in your loop you are creating 4 separate functions that can be visualized as..

如果你想象你的循环中有4个锚你就会创建4个独立的函数可以被想象成。

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

I would consider looking into scope and closures with javascript as if you go down this road and don't understand exactly what is happening you can run into massive problems from unexpected behavior.

我将考虑使用javascript来研究范围和闭包,就好像沿着这条路走下去,不知道到底发生了什么一样,您可能会因为意外的行为而遇到巨大的问题。

#3


2  

When the onclick event is triggered, the anonymous function is called and it refers to the same variable i that was used in the loop and it holds the last value of i, that is 4.

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

The solution to your problem is to use a function returning a function:

解决您的问题的方法是使用函数返回一个函数:

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