关于javascript:在for循环中访问函数外部的变量(对象)

access variables(object) outside function within a for loop

本问题已经有最佳答案,请猛点这里访问。

我的问题可能听起来像一个关于关闭的问题但它确实有一些区别。

1
2
3
4
5
6
7
8
9
10
11
12
var people = [{name: 'john', age: 20},
    {name: 'james', age: 25},
    {name: 'ryan', age: 19}];
var mainDiv = document.createElement('div', {id: 'mainDiv'});
for (var i = 0; i < people.length; i++) {
    var button = document.createElement('button', {}, mainDiv);
    var person = people[i];
    button.onClick = function (e) {
        console.log('printing name');
        console.log(person.name);
    };
}

这只是我编写的一个例子。 由于person变量指向people数组的最后一个对象,因此在for循环结束时,它总是在单击按钮时打印出最后一个元素。 然而,我想要实现的是在单击每个按钮时打印出每个相应人的姓名。 我该怎么做才能使内部'onClick'函数指向正确的对象?


您可以使用立即调用的函数表达式将闭包分解为外部人员,例如:

1
2
3
4
5
6
button.onclick = (function (p) {
      return function (e) {
        console.log('printing name');
        console.log(p.name);
      };
}(person));

顺便说一句,javascript区分大小写,因此您要分配给onclick属性,而不是onClick。

您似乎也在使用或假设DOM规范的扩展,例如

1
document.createElement('div', {id: 'mainDiv'});

这不是标准的JavaScript,似乎假设主机方法的扩展。


1
2
3
4
5
6
7
8
9
10
11
for (var i = 0; i < people.length; i++) {
    var button = document.createElement('button', {}, mainDiv);
    var person = people[i];

    var clickfunc=function(name){return function(e){
        console.log('printing name');
        console.log(name);
    }}

    button.onclick = clickfunc(person.name);
}

你是对的,这不是一个典型的闭包函数,而是一个常见的误用闭包,其中变量应该是预先绑定的。

调用clickfunc函数时,person.name将传递给调用堆栈,其值为AT THE TIME OF CALLING。函数本身返回另一个函数,因此在按钮实际单击之前,您不会调用它。

我还纠正了onClick到onclick。


代码中的闭包需要捕获新上下文中的person对象。这可以通过创建一个返回函数(内部)并将参数传递给该外部函数的新函数(外部)来完成。最好使用attachEventaddEventListener而不是onclick附加事件。对maindDiv.onclick的附加调用将覆盖元素上的任何事件处理程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var people = [{name: 'john', age: 20},
        {name: 'james', age: 25},
        {name: 'ryan', age: 19}];
var mainDiv = document.createElement('div', {id: 'mainDiv'});
for (var i = 0; i < people.length; i++) {
    var button = document.createElement('button', {}, mainDiv);
    var person = people[i];
    attachEvent(button,"click",bindClickEvent(person));
}

//Outer function
function bindClickEvent(person){
   //inner function retains context of outer function
   return function(){
        console.log('printing name');
        console.log(person.name);
   };
}

function attachEvent(elem, event, func){
    if(elem.attachEvent){
      elem.attachEvent("on" + event, func);
    }else{
        elem.addEventListener(event, func);
    }
}

JS小提琴:http://jsfiddle.net/vD5B7/1/