简体   繁体   中英

Variable keeps changing after function is assigned to event handler

I have a bunch of elements on a page, all of whose ID's are stored in an array called ids[] .

I have initialized a third-party DOM script for each of these divs that detects when the element has been dragged. The next step is to assign a function to the onDrag event of each element.

For simplicity's sake, I'd simply like to show a popup dialog that states the ID of the element that was dragged. I am iterating through my array as follows:

for (i=0;i<ids.length;i++)
{
document.getElementById(ids[i]).onDrag = function(){alert(ids[i])}
}

This all seems well and good, but toggling the drag event of any of my elements causes a dialog to popup that states the ID of the last element in the array. In other words, it looks like the above function in my iteration is always being evaluated for the last index in my array. I feel like I am missing something very simple here but this issue is driving me nuts.

The thing you've encountered is called closure and it is an essential part of Javascript.

A closure is an expression (typically a function) that can have free variables together with an environment that binds those variables (that "closes" the expression).

What happens is that the anonymous function assigned to ondrag closes over it's environment including variable i . As a consequence whenever i changes outside of this function, i will contain the new value inside accordingly.

The way you can workaround this behavior in the current context is to create another scope with an additional self-executing function.

for (var i=0; i<ids.length; i++) {
  document.getElementById(ids[i]).onDrag = (function(i){  // <- i is a parameter
    return function() {
      alert(ids[i]);  // <- i will be the inner value saved from outside
    };
  })(i);  // <- invoke immidiately with the i from outside
}

You can read more on the topic: Use Cases for JavaScript Closures by @kangax

Do the following changes,

for (...){
    SetOnDrag(ids[i]);
}

function SetOnDrag(id)
{
    document.getElementById(id).onDrag = function() { alert(id); };
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM