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

时间:2014-01-20 00:48:28

标签: javascript object pointers

我的问题可能听起来像一个关于关闭的问题,但确实有一些不同。

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'函数指向正确的对象?

3 个答案:

答案 0 :(得分:1)

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 to onclick。

答案 1 :(得分:1)

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

button.onclick = (function (p) {
      return function (e) {
        console.log('printing name');
        console.log(p.name);
      };
}(person));

顺便提一下,javascript区分大小写,因此您要分配到 onclick 属性,而不是 onClick

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

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

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

答案 2 :(得分:0)

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

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/