2
function addHandler() {  
    var el = document.getElementById('el');  
    el.onclick = function() {  
        this.style.backgroundColor = 'red';  
    }  
}

The code above was included in a Mozilla blog post on JavaScript and states that the above code causes a memory leak.

Could someone explain it more than:

Because the reference to el is inadvertently caught in the closure created for the anonymous inner function. This creates a circular reference between a JavaScript object (the function) and a native object (el).

Thanks!

tgandrews
  • 12,349
  • 15
  • 43
  • 55

3 Answers3

2

with my interpretation, this isn't a memoryleak per-se (sometimes you can't solve your problem without a construct like this, but they are far more complicated), but its not good, because your creating the onclick function everytime new, which keeps a 'link' to its parent (what a closure does). This code would be far better;

function clickHandler(){
    this.style.backgroundColor = 'red';
}
function addHandler() {  
    var el = document.getElementById('el');  
    el.onclick = clickHandler           
}

this way, no closure is created, no unused references are made and no function will be generated multiple times.

japrescott
  • 4,736
  • 3
  • 25
  • 37
  • The answer, is then all closures when they are created keep a link to their parent. Hence the `onclick` closure references `el` which in turn references `el`? – tgandrews Feb 09 '12 at 09:05
  • in your questions code, the onclick function has a link to its parent and therefor has access to the ´el´ variable. Inside the function, the ´el´ variable is equivalent to the ´this´, hence you've got a little circle. – japrescott Feb 09 '12 at 09:13
1

@thg435: It looks like that might be a result of using eval.

Executing the following in Firefox or Chrome with a watch on foo while breaking at debugger reports foo's value as undefined.

(function () {
  var foo = "bar";
  return function() {
    debugger;
  };
})()();

While executing the following reports foo's value as "bar" while breaking at debugger:

(function () {
  var foo = "bar";
  return function(_var) {
    debugger;
    return eval(_var);
  };
})()('foo');

It would be great to get a definitive answer on this.

Scott Christopher
  • 6,458
  • 23
  • 26
0

The question is: does a closure capture all variables in the current scope or only those explicitly mentioned? Consider:

function makeClosure() {
   var foo = 1;
   var bar = ...some heavy object...

   return function() {
       do_something_with(foo)
   }
}

The inner function captures foo, does it capture bar as well? I guess, yes, because the following prints the correct value:

function makeClosure(bar) {
   var foo = 1;

   return function(name) {
       console.log(foo);
       console.log(eval(name));

   }
}

makeClosure('print_me')('bar')

So, in your example, el gets "inadvertently" caught in the closure (onclick handler). Thus, the closure refers to el, and el.onclick refers to the closure, qed.

georg
  • 211,518
  • 52
  • 313
  • 390