作用域和将参数传递给动态创建的事件处理程序时出现问题
Issue with scope and passing parameters to dynamically created event handler
在下面的代码中,您将看到我正在尝试为image.onclick
定义一个需要额外参数的事件处理程序,我在while循环中声明这些参数,希望JavaScript以这种方式定义范围,但它没有。 基本上,这里的所有事件处理程序都获取了我提供给变量id
和section_id
的最后一个值。关于如何处理我想动态生成这些处理程序的情况的任何想法?
function handlePicturesResult(){
if (req.readyState == 4) { // Complete
if (req.status == 200) { // OK response
var el = document.getElementById('pictureHolder');
while( el.hasChildNodes() ){
el.removeChild(el.lastChild);
}
var tempObject = JSON.parse(req.responseText);
var pictures = tempObject.images;
var i=0;
while(i<pictures.length){
var picIndex = i;
var image= new Image(120,80);
image.src = 'images/' + pictures[i].url;
image.width = 120;
image.height = 80;
var id = pictures[picIndex].id;
var section_id = pictures[picIndex].sectionId;
image.onclick = function(event){
deleteImage(event,id,section_id);
}
var txtNode = document.createTextNode(pictures[picIndex.valueOf()].id);
el.appendChild(image);
el.appendChild(txtNode);
i++;
}
} else {
alert("Problem: " + req.statusText);
}
}
}
包解决了另一个问题!
image.onclick = function(id, section_id){
return function(event) {
deleteImage(event,id,section_id);
}
}(id, section_id);
外部函数立即运行(注意末尾带有参数的括号),它返回内部函数,该函数在其范围内保留变量的副本,因为它们在循环的迭代中。
JavaScript 按值传递非对象变量,因此通过将id
和section_id
传递给外部函数,您可以在该函数内创建它们的副本。 当您创建并返回内部函数时,该内部函数将创建时范围内的所有变量(这是闭包的核心),包括 id
和 section_id
的局部变量副本。 具有唯一作用域的内部函数将成为该元素的事件处理程序。
你需要使用闭包。https://developer.mozilla.org/en/JavaScript/Guide/Closures
image.onclick = function(id, s_id){
return function(event){
deleteImage(event, id, s_id);
}
}(id, section_id)
javascript 中的范围可以在函数的大括号内定义,这就是为什么让外部函数使用传递给它的参数执行将在您需要它们的循环中的特定时间保留这些变量的值。
如果没有它们,id 和 section_id 的值将始终引用它们在上次迭代时的值。
这是一个经典的JavaScript问题,源于对函数作用域缺乏理解。在这一行上:
deleteImage(event,id,section_id);
传递给deleteImage
的参数没有理由保留创建回调时的值。变量id
和section_id
绑定到handlePicturesResult
的作用域;它们是存在于该空间中的变量,每个变量只有一个副本。因此,当回调运行时,它将使用这些特定变量和它们当前引用的值(来自循环的上次迭代)。
解决方案是将变量放入一个范围,该范围在循环的每次迭代中"保存"其值。函数在 JS 中提供唯一的此类作用域。我不会重复已经提供的出色解决方案。另一种方法是使用 jQuery 的 each
进行迭代,你就不会再遇到这个问题了:
$.each(pictures, function(i, picture) {
var image= new Image(120,80);
var id = pictures.id;
var section_id = picture.sectionId;
var txtNode = document.createTextNode(id);
image.width = 120;
image.height = 80;
image.src = 'images/' + picture.url;
image.onclick = function(event){
deleteImage(event, id, section_id);
}
el.appendChild(image);
el.appendChild(txtNode);
});
- 假定
pictures
是一个数组。
- keyup事件处理程序更改焦点不适用于快速键入
- 提示使用服务器端事件处理程序激活JavaScript
- 将事件处理程序绑定到任何可能的事件
- 正在将事件处理程序添加到不存在的类
- 在循环中附加事件处理程序时出现浏览器性能问题
- 在同一个javascript事件处理程序中调用不同的函数
- 有没有一种方法可以让内联事件处理程序在元素创建后立即执行
- 检查事件处理程序参数
- 实现延迟的jquery更改事件处理程序
- 如何使用Node.js在JavaScript模块文件之间使用事件处理程序
- 如何使jQuery的“bind”或“on”事件处理程序幂等
- 带有参数的Javascript事件处理程序
- Jquery事件处理程序仅适用于匿名函数
- 如何从另一个处理程序内部取消JavaScript事件处理程序函数的执行
- 如何在jQuery事件处理程序中存储和重用超时
- 如何向onClick事件处理程序传递一个接受参数的函数,并且仍然将该函数绑定到组件's”;这个“;上下文
- 异步处理所有事件处理程序的方法
- jsplumb中的Click事件处理程序丢失“;这个“;对象
- 构造函数中的事件处理程序与构造函数外的事件处理函数的行为不同
- 如何在事件处理程序的回调中防止Default