views:

261

answers:

3

hey guys, someone from doctype sent me here.
long story short:

var o="before";
x = function() //this needs to be an anonymous function
{
  alert(o); //the variable "o" is from the parent scope
};
o="after"; //this chages "o" in the anonymous function

x();
//this results in in alert("after");
//which is not the way i want/need it

in reality my code is somewhat more complex.
my script iterates through many html objects and adds an event listener each element.
i do this by declaring an anonymous function for each element and call another function with an ID as argument. that ID is represented by the "o"-variable in this example.

after some thinking i understand why it is the way it is,
but is there a way to get js to evaluate o as i declare the anonymous function without dealing with the id attribute and fetching my ID from there?

my full source code is here: http://pastebin.com/GMieerdw the anonymous function is on line 303

+3  A: 

You can try using a self-invoking function like this:

var o = 0;
for(var i=0;i<elements.length;i++){
    (function(obj,variable){
        obj.onclick = function(){
            alert(variable);
        }
    })(elements[i],o);
    o++;
}

That should alert "o" at whatever value it was during the loop, instead of alerting the final value of "o".

I hope this helps in some way.

tau
soo... i tried the other approach first because this one looks a bit difficult. but... IT WORKS!! thank you very much. i nearly lost all hope
tkSimon
im glad i could help in some way. both methods are very similar.
tau
+4  A: 

You need to create a closure of your variable o. You can do this by assigning a function that accepts a value returns a function which uses that value. Your example can be modified like this to get the desired effect:

var o="before";
x = function(inner) {
    return function()
    {
      alert(inner);
    }
} (o); //here, the anonymous function is called, which will return another function which uses o
o="after";

x();//prints "before"

For a more detailed description, see the MDC article, which has a section about using closures with loops.

This same technique can be applied in your loop. Something like this is what you would want to do:

var fn = function(x, y) {
    return function() {
        rr_download_start(x, y);
    }
} (i, this);
link.addEventListener('click', fn ,false);
wsanville
It can become a little confusing if you do, but you can make `x=function(o){return function() { alert(o); }}(o);` too, that way the name of the variable doesn't change...
gnarf
yes, it's quite similar to tau's solution: an anonymous function in an anonymous function. i didn't try this one but i'm sure it also works! his solution is just a bit more what i need.
tkSimon
A: 

One way is to create a currying function:

function curry(fun, arg) {
  return function() {
    return fun(arg);
  };
};

// start loop 
var o="before";
x = curry(function(o) {
  alert(o);
}, o);
o="after";

x(); // "before"

Another way is to use an external data source - since this will depend on where the function was called, you can store the value in the DOM node to which you bind the handler. This way you can use a single function instead lots of anonymous functions. This technique has a few caveats (circular references can cause memory leaks in IE6), but frameworks can have a nice clean wrapper for it. E. g. in jQuery you can write:

function doStuff() {
  alert($(this).data('o'));
}

// start loop
var o="before";
someDomElement.data('o', 'before');
someDomElement.bind('someEvent', doStuff);
o="after";

someDomElement.trigger('someEvent'); // "before"
Tgr
this also sounds very promising, thanks
tkSimon