开发者

JS: variable inheritance in anonymous functions - scope

开发者 https://www.devze.com 2022-12-30 00:49 出处:网络
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

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 ex开发者_开发知识库ample.

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.


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);


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.


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"
0

精彩评论

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

关注公众号