Hacker News new | past | comments | ask | show | jobs | submit login

When addHandler is called, the anonymous function expression is evaluated and its result is assigned to el.onclick. Thus, el contains a reference to the newly created function. However, when the function is created, it captures the environment in which it is defined, including the variable el. Thus, el points to the function, and the function (closure) points to el. This is the circular reference that IE can't handle.



Maybe I'm missing something, but the function doesn't point to `el`. `el` just exists in a lower execution context on the stack. If a variable inside the anonymous function referenced `el` directly, then a closure would be formed over `el`. In this instance `this` is just assigned when the function is called.


I'm not sure whether you're saying the code is wrong or you can't understand how that code creates the circular reference. This problem was widely known and stopped being a problem in IE8 I believe. Maybe it was IE7. A while ago anyway. That code looks like the type of circular reference that would cause it. You used to be able to download tools to watch for the memory leak.

From what I remember the closure will keep a reference to el even though it will never use it, which means el won't be garbage collected when removed from the dom, which means the closure won't be removed from the onclick to free up el. Hence a circular reference. IE6's javascript garbage collector couldn't detect that.

The article is old. Here's an article from MS in 2005 describing the problem in more detail:

http://msdn.microsoft.com/en-us/library/Bb250448

Apologies if you understood that and were just saying the code is wrong, but it looks right to me. Not that I can be bothered to fire up IE6 to test it out.

EDIT: Some more detail about the definitely historical leak from SO, it also turns out it was only partially fixed in IE7:

http://stackoverflow.com/questions/1999840/javascript-circul...


Thanks for the info. So it was the dreaded IE 6 that would not release things when you reloaded or went to another page. I was wondering why the base article here said you had to restart the browser completely, as I could think of no reason to carry over objects between pages (outside of browser/external persistence). At least IE 7 implemented the obvious "clean up between pages" operation.

Die, Explorer, die! :-)


One more and then I'll shut up :)

It looks like my previous example was affected by eval.

The following reports foo's value as undefined while breaking for the debugger statement in Firefox and Chrome:

  (function () {
    var foo = "bar";
    return function() {
      debugger;
    };
  })()();
While the following reports foo's value as "bar" while breaking for the debugger statement:

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


The first example there allows the JS engine to prove to itself that no one uses foo, so it optimizes the reference out of the closure to save memory. That's an optimization (and the fact that the debugger doesn't disable it is actually a bug); the language semantic is that all closed-over variables are available to the closure function body.


So to answer myself, it does look like a reference is maintained despite no direct references existing within the inner function (unless eval is causing the reference to be maintained):

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


It looks exactly like eval is causing the reference to be maintained.

If you change the inner function call parameter 'foo' to ('alert("hi")') you'll see the reference to foo='bar' is still maintained in the inner function. So there is no -direct- reference to foo in the inner function, but there isn't even an -indirect- reference being made in the call to eval. The reference to foo is being maintained purely because eval "might" require it. Or so it appears.

If the return eval(_var) statement is replaced with alert('blah') we're back to foo being undefined in the inner function. So I've definitely got my finger pointed at eval on this one.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: