在for循环中分配点击处理程序

Phi*_*lip 72 javascript jquery closures jquery-selectors

我有几个div的#mydiv1,#mydiv2,#mydiv3,...,想点击处理分配给他们:

$(document).ready(function(){
  for(var i = 0; i < 20; i++) {
    $('#question' + i).click( function(){
      alert('you clicked ' + i);
    });
  }
});
Run Code Online (Sandbox Code Playgroud)

但是,我没有'you clicked 3'在点击时显示#mydiv3(就像其他每次点击一样)'you clicked 20'.我究竟做错了什么?

Har*_*men 131

在Javascript 中用循环创建闭包是一个常见的错误.你需要有这样的回调函数:

function createCallback( i ){
  return function(){
    alert('you clicked' + i);
  }
}

$(document).ready(function(){
  for(var i = 0; i < 20; i++) {
    $('#question' + i).click( createCallback( i ) );
  }
});
Run Code Online (Sandbox Code Playgroud)

2016年6月3日更新:由于这个问题仍然有所吸引力,ES6也越来越受欢迎,我建议采用现代解决方案.如果你编写ES6,你可以使用let关键字,这使得i变量本地化为循环而不是全局变量:

for(let i = 0; i < 20; i++) {
  $('#question' + i).click( function(){
    alert('you clicked ' + i);
  });
}
Run Code Online (Sandbox Code Playgroud)

它更短更容易理解.

  • 实际上作为解释,应该写入引用"i"的匿名函数仅在循环的上下文中执行而不是立即运行.这意味着,当onclick事件发生时,"i"实际上处于循环的结束状态.您可以通过将"i"作为本地参数传递来避开这种情况(正如此回调解决方案所做的那样). (7认同)
  • 我*真的*不会调用`callback`"callback".这不是回调.它是*创建*回调的工厂. (3认同)

Don*_*ald 12

为了澄清,我等于20,因为在循环结束之前,click事件才会被触发.


小智 7

$(document).ready(function(){
  for(var i = 0; i < 5; i++) {
   var $li= $('<li>' + i +'</li>');
      (function(i) {
           $li.click( function(){
           alert('you clicked ' + i);
         });
      }(i));
      $('#ul').append($li);
  }
});
Run Code Online (Sandbox Code Playgroud)


Ric*_*ves 6

使用on附加“点击”处理程序,您可以使用事件数据来传递您的数据,例如:

for(var i = 0; i < 20; i++) {
  $('#question' + i).on('click', {'idx': i}, function(e) {
    alert('you clicked ' + e.data.idx);
  });
}
Run Code Online (Sandbox Code Playgroud)

for(var i = 0; i < 20; i++) {
  $('#question' + i).on('click', {'idx': i}, function(e) {
    alert('you clicked ' + e.data.idx);
  });
}
Run Code Online (Sandbox Code Playgroud)
//
// let's creat 20 buttons
//

for(var j = 0; j < 20; j++) {
	$('body').append($('<button/>', {type: 'button', id: 'question' + j, text: 'Click Me ' + j}))
}

//
// Passing data to the handler
//
for(var i = 0; i < 20; i++) {
  $('#question' + i).on('click', {'idx': i}, function(e) {
    console.log('you clicked ' + e.data.idx);
  });
}
Run Code Online (Sandbox Code Playgroud)