开发者

pass variables to an event javascript - no closures, no jq, avoid evals & such

ok, this has been addressed by everybody, but yet I feel no closer to understanding what to do.

I want to have a loop that sets a bunch of click handlers and have each handler given unique parameters. I'm doing somehting like this now:

for (thisThing in things){
    myDiv=document.createElement('img');

    myDiv.onclick=function(){
        // do somehting!
        // but don't do anything with "thisThing" 
        // because it's got the wrong value in it by the time you call it!
        // but this function has to have the value of "thisThing" to work, dammit!
    }
}
  • All over the place the solution for this is said to be closures - wow great! except closures break ie (right?)
  • Elsewise, I can eval the code on the spot, baking i开发者_JAVA百科n the varibles, but that seems ugly at best, and seems like it might break some thing

So what does this leave me? Are closures ok? is evaling ok? AM I THE ONLY PERSON DYNAMICALLY CREATING BUTTONS ON THE WEB?!? Any help will be much appreciated. sorry about the elementary &, in fact, frequently answered question.

this page has the most complete answer I've found thus far, however, it suggests that closures are the solution for all time. Curses! http://www.howtocreate.co.uk/referencedvariables.html


Closures do not break IE.

(function(someThing) {
    myDiv.onclick=function(){
       // Access it as "someThing"
    }
})(thisThing);

jsFiddle.

The problem is the function assigned to the onclick property creates a closure where it has access to its parents variables.

By the time you are ready to click an element, its thisThing has been incremented to the final value that terminates the loop (the last property iterated over in your case) because it accesses the outer variable, not a copy.

By creating a new closure with a new self invoking function and passing thisThing, its value becomes the variable someThing and lives inside of the inner function only.

This is one of the ways of mitigating this known problem.

Note that in IE6 & 7 there is a memory leak. Consult RobG or Raynos's answer for a solution to this issue.


The problem is creating functions in loops is BAD. A little bit of refactoring makes your problem disappear.

function createDiv(thing) {
    var div = ...
    div.onclick = ...
}

for (thisThing in things) {
    createDiv(thisThing);
}

But this still leaks memory in older versions of IE.

It's because of this code :

var div = ...;
div.onclick = function() { ...;

The div has a refence to the function and the function has a reference to the div. This is a circular reference. To remove this problem you need a callback factory.

function createDiv(thing) {
    var div = ...
    div.onclick = createCallback(thing);
}

function createCallback(thing) {
    return function() {
         ...
    };
}

This means your onclick callback has NO reference to your div element.


I want to have a loop that sets a bunch of click handlers and have each handler given unique parameters. I'm doing somehting like this now:

> for (thisThing in things){
>     myDiv=document.createElement('img');
> 
>     myDiv.onclick=function(){
>         // do somehting!
>         // but don't do anything with "thisThing" 
>         // because it's got the wrong value in it by the time you call it!
>         // but this function has to have the value of "thisThing" to work,
> dammit!
>     } }

All over the place the solution for this is said to be closures

No, you don't want closures at all. You are trying to not have closures.

except closures break ie (right?)

Wrong.

There was an issue with IE and circular references involving DOM elements causing memory leaks. That issue has largely been fixed, however it is much misunderstood. For example:

function addListener(element) {
    var someVar = ...;
    element.onclick = function() {
        // this function has a closure to someVar
    };
}

Causes a cicular reference involving the closure to someVar when addListener is called. There was some pretty simple fixes for that. What you want to do is not have a closure to someVar, but use the value. That can be done a number of ways, but the simplest is:

function addListener(element) { var someVar = ...; element.onclick = (function(differentVar) { alert(differentVar); })(someVAr); }

So now the value of someVar is passed to differentVar, which is a local variable of the inner function. Of course the inner function may still have a closure to someVar, but the use of the use of an immediately called anonymous function breaks the closure between differentVar and someVar.

As a one-of, there is no issue with the closure anyway. But where you are attaching a number of listeners and they all have a reference to someVar, then they all share the same value. Using an immediately called anonymous function in between breaks that chain.

Edit

Sorry, that last example is incorrect, my bad.

function addListener(element) {
    var someVar = ...;
    element.onclick = (function(differentVar) {
        return function() {
          alert(differentVar);
        };
    })(someVAr);
}


Closures don't break IE.

for (thisThing in things){
    if(!things.hasOwnProperty(thisThing)) continue;

    var myDiv = new document.createElement('img');
    myDiv.onclick = (function(thing){
        // Instance specific vars and other thigns
        return function() {
            // More stuff
        }
    })(thisThing);
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜