[英]Javascript - Issue with scope and passing parameters to dynamically created event handler
In the code below you will see that I am trying to define an event handler for image.onclick which takes extra parameters, i was declaring those parameters inside of the while loop hoping javascript defined scope this way but it does not. 在下面的代码中,您将看到我正在尝试为image.onclick定义一个事件处理程序,它需要额外的参数,我在while循环中声明了这些参数,希望javascript定义范围这样,但事实并非如此。 Basically all of the event handlers here are getting the very last value that i give to variables id and section_id. 基本上这里的所有事件处理程序都获得了我给变量id和section_id的最后一个值。 Any idea on how to handle a situation where i want to be generating these handlers dynamically? 关于如何处理我想要动态生成这些处理程序的情况的任何想法?
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);
}
}
}
Yet another problem solved by closures ! 关闭解决了另一个问题!
image.onclick = function(id, section_id){
return function(event) {
deleteImage(event,id,section_id);
}
}(id, section_id);
The outer function is run at once (notice the parentheses with arguments at the end), and it returns the inner function, which keeps in its scope a copy of the variables as they are at that iteration of the loop. 外部函数立即运行(注意末尾带有参数的括号),并返回内部函数,该函数在其范围内保留变量的副本,就像它们在循环的迭代中一样。
JavaScript passes non-object variable by value, so by passing id
and section_id
to the outer function, you create a copy of them inside that function. JavaScript按值传递非对象变量,因此通过将id
和section_id
传递给外部函数,可以在该函数内创建它们的副本。 When you create and return the inner function, that inner function keeps in scope all variables that are in scope at the time of its creation (this is at the heart of what a closure is ), including the local-variable copies of id
and section_id
. 当您创建并返回内部函数时,该内部函数会在其创建时保留范围内的所有变量(这是闭包的核心),包括id
和section_id
的局部变量副本。 The inner function, with its unique scope, becomes the event handler for that element. 内部函数及其唯一范围成为该元素的事件处理程序。
You need to use a closure. 你需要使用一个闭包。 https://developer.mozilla.org/en/JavaScript/Guide/Closures 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)
Scope in javascript can be defined within the curly braces of a function, which why having an outer function execute with arguments passed to it will preserve the value of these variables at the specific time in the loop you need them. javascript中的范围可以在函数的花括号中定义,这就是为什么外部函数执行时传递给它的参数将在你需要的循环中的特定时间保留这些变量的值。
Without them, the values of id and section_id will always reference the value they have at last iteration. 没有它们,id和section_id的值将始终引用它们在最后一次迭代时所具有的值。
This is a classic JavaScript problem that stems from lack of understanding about function scope. 这是一个典型的JavaScript问题,源于对功能范围缺乏了解。 On this line: 在这一行:
deleteImage(event,id,section_id);
there is no reason that the parameters passed to deleteImage
should retain the values they had at the time when the callback was created. 没有理由认为传递给参数deleteImage
应保留他们在当时创建回调时的值。 The variables id
and section_id
are bound to the scope of handlePicturesResult
; 变量id
和section_id
绑定到handlePicturesResult
的范围; they are variables that exist within that space, and there is only ever a single copy of each. 它们是该空间中存在的变量,每个变量只有一个副本。 Thus, when the callback runs, it will use those specific variables and the values they currently refer to (from the loop's last iteration). 因此,当回调运行时,它将使用那些特定变量及它们当前引用的值(来自循环的最后一次迭代)。
The solution is to get the variables into a scope that "saves off" their values every iteration of the loop. 解决方案是将变量放入一个范围,在每次循环迭代时“保存”它们的值。 Functions provide the only such scopes in JS. 函数在JS中提供了唯一的这样的范围。 I won't repeat the excellent solutions already provided. 我不会重复已经提供的优秀解决方案。 An alternative is to use jQuery's each
for iterations, and you won't have this problem again: 另一种方法是使用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
is an array. 假设pictures
是一个数组。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.