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'});