Javascript 变量作用域和事件处理程序
请参阅JSFIDLE:Javascript 变量作用域和事件处理程序,javascript,scope,event-handling,dom-events,Javascript,Scope,Event Handling,Dom Events,请参阅JSFIDLE: 函数MyFunc(){ 对于(var i=0;i
函数MyFunc(){
对于(var i=0;i<2;i++){//i=0,1
var myDiv=$('');
myDiv.click(函数(e){
警报(i);//两个div都警报“2”,而不是我预期的0和1
});
$('body').append(myDiv);
}
}
var myFunc=新的myFunc();
我希望在单击div时,它们分别向“0”和“1”发出警报,但它们都向“2”发出警报
当我单击div并触发事件时,处理程序如何以及在何处查找变量I
我知道添加闭包可以实现我的目标。但是为什么呢?您需要一个闭包,因为所有事件处理程序函数都引用同一个变量
i
。for
循环将更新此值,循环完成后,变量包含2
。然后,当有人单击其中一个div时,它将访问该变量
要解决这个问题,每个事件处理程序都需要是一个闭包,它有自己的变量i
,该变量包含创建闭包时值的快照。函数MyFunc(){
function MyFunc() {
for (var i = 0; i < 2; i++) { // i= 0, 1
(function(j) {
var myDiv = $('<div>');
myDiv.click(function(e) {
alert(j);
});
$('body').append(myDiv);
})(i);
}
}
var myFunc = new MyFunc();
对于(var i=0;i<2;i++){//i=0,1
(职能(j){
var myDiv=$('');
myDiv.click(函数(e){
警惕(j);
});
$('body').append(myDiv);
})(i) );
}
}
var myFunc=新的myFunc();
上面的代码是如何让它正常工作的。如果没有闭包,则始终是i的最后一个值。我们要做的是将i发布到闭包中,让运行时“记住”那个时刻的值。我建议您阅读
JavaScript提升声明。这意味着两个var语句
函数声明将被移动到它们的封包的顶部
范围
正如@Barmar在上面的回答中所说,变量i
正被两个事件处理程序引用
应该避免在循环中声明函数。下面有一些代码可以满足您的需要
我假设您正在使用jQuery
function MyFunc() {
for (var i = 0; i < 2; i++) { // i= 0, 1
var myDiv = $('<div>');
$('body').append(myDiv);
}
$('div').on('click', function() {
alert($(this).index());
});
}
var myFunc = new MyFunc();
函数MyFunc(){
对于(var i=0;i<2;i++){//i=0,1
var myDiv=$('');
$('body').append(myDiv);
}
$('div')。在('click',function()上{
警报($(this.index());
});
}
var myFunc=新的myFunc();
调用“alert()”发生在for循环完成之后,这意味着“i”的值将是该循环完成之后的最后一个值。为了捕获“i”的单个值,必须通过创建新函数为每个值创建闭包:
function MyFunc() {
function alertFn(val) {
return function () {
alert(val);
};
}
for (var i = 0; i < 2; i++) {
var myDiv = $('<div>');
myDiv.click(alertFn(i));
$('body').append(myDiv);
}
}
var myFunc = new MyFunc();
函数MyFunc(){
功能警报FN(val){
返回函数(){
警报(val);
};
}
对于(变量i=0;i<2;i++){
var myDiv=$('');
myDiv.click(警报fn(i));
$('body').append(myDiv);
}
}
var myFunc=新的myFunc();
闭包在传递到函数时捕获“i”的值,从而允许alert()显示您期望的值。这是标准方法吗?如果循环体相当长,我们是否仍将其包装在匿名函数中?这是常用的习惯用法。但是如果你喜欢更长的函数,你可以使用Zenwolf的风格。我可以看到人们通常是这样写的。尽量不要在大循环中这样做。我的意思是喜欢(var I=0;I<1000;I++)。你说你知道正确的编写方法,你只是想解释一下为什么需要这样做。我不确定我能写什么代码来说明答案——你的代码做得很好。
function MyFunc() {
function alertFn(val) {
return function () {
alert(val);
};
}
for (var i = 0; i < 2; i++) {
var myDiv = $('<div>');
myDiv.click(alertFn(i));
$('body').append(myDiv);
}
}
var myFunc = new MyFunc();