tgandrews
tgandrews

Reputation: 12670

JavaScript memory leak explanation

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!

Upvotes: 2

Views: 191

Answers (3)

Scott Christopher
Scott Christopher

Reputation: 6516

@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.

Upvotes: 1

georg
georg

Reputation: 214959

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.

Upvotes: 0

japrescott
japrescott

Reputation: 5025

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.

Upvotes: 2

Related Questions