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

Javascript 访问for循环中函数外部的变量(对象),javascript,object,pointers,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

我的问题听起来像是关于结束的问题,但它确实有一些区别

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);
    };
}
var people=[{name:'john',年龄:20},
{姓名:“詹姆斯”,年龄:25},
{姓名:'ryan',年龄:19}];
var mainDiv=document.createElement('div',{id:'mainDiv'});
for(var i=0;i

这只是我编的一个例子。由于person变量指向people数组的最后一个对象,因此在for循环的末尾,它总是在单击按钮时打印出最后一个元素。然而,我想要实现的是在单击每个按钮时打印出每个对应人员的姓名。如何使内部“onClick”函数指向正确的对象?

代码中的闭包需要在新上下文中捕获
person
对象。这可以通过创建一个新函数(外部)来实现,该函数返回一个函数(内部),并将参数传递给该外部函数。另外,最好使用
attachEvent
addEventListener
而不是
onclick
附加事件。对
maindDiv.onclick的其他调用将覆盖元素上的任何EventHandler

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);
    }
}
var people=[{name:'john',年龄:20},
{姓名:“詹姆斯”,年龄:25},
{姓名:'ryan',年龄:19}];
var mainDiv=document.createElement('div',{id:'mainDiv'});
for(var i=0;i
JS Fiddle:
for(var i=0;i
你是对的,这不是一个典型的闭包函数,而是对闭包的一种常见误用,在这里变量应该是预先绑定的

调用clickfunc函数时,person.name将与调用时的值一起传递到调用堆栈。函数本身返回另一个函数,因此在实际单击按钮之前,您不会调用它


我还将onClick改为onClick。

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

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,并且似乎假定了对宿主方法的扩展

我发现我的代码写错了。下面是更正后的JSFIDLE版本。我不确定您从哪里获得
createElement
中的参数,它是自定义版本吗?恐怕它只需要一个参数,一个标记名。ID不会出现在小提琴上。@elclars哦,你是对的,我把它与dojo的domConstructor混淆了,dojo的domConstructor一次使用三个参数来最小化代码行。你可以通过将
var person
移动到函数顶部,让问题更加明显,因为这是有效声明变量的地方。即使在循环中声明
var person
,循环的所有迭代都只共享一个变量
person
。所有的点击处理程序都会关闭这个相同的变量,这就是为什么它们都以最后一个值结束。这将被许多经验丰富的JavaScript开发人员视为最佳实践。这似乎是一个dup问题。我可以结束这个问题。感谢所有的答案,答案都写得很好!是的,我把创建元素和dojo混淆了。感谢您指出:)挑剔:OP代码中的事件处理程序已经是一个闭包。解决方案是创建一个新的上下文,在该上下文中变量的值不变。闭包允许外部变量的可见性。根据定义,它不绑定值。Felix是对的,通过创建新的上下文,或者用我的话说,通过在调用堆栈上保留值,变量在定义时绑定,而不是在调用时绑定。同样,更改onclick也很好且简洁。这是一个视角和思维模式的问题。事件触发是DOM,onclick也是JavaScript对象中的一个属性。函数在JavaScript中是一流的,可以轻松地分配给事件处理程序。@Schien我建议不使用onclick的原因是,如果在元素中添加一个额外的
onclick
事件处理程序,它将覆盖现有的事件handler@FelixKling谢谢你的更正。人们用来描述闭包的术语似乎很多。
document.createElement('div', {id: 'mainDiv'});