4
window.onload = function() {
   var a = function(x) {
       console.log(x);
   };
   document.onclick = function() {
       a(1);
   };
   document.onkeyup = function() {
       a(2);
   };
};

I understand fairly well why this works, but not how.

When window.onload ends, a is destroyed, but the function it referenced is still available to the event handlers, because it was declared in a higher scope, if I understand this correctly.

Does the interpreter keep a hidden reference to the function in the background, or does the interpreter somehow inline the function? Is this type of code to avoid a global variable efficient? Thanks.

  • I believe this is an effective way to avoid global variables. [Closure](http://stackoverflow.com/search?q=%5Bjavascript%5D+closure) is an amazing feature in JavaScript. – Passerby Feb 04 '13 at 08:02
  • Any answer to this question would require highly intricate details of the implementation of a Javascript engine. Frankly I think you're unlikely to find what you're looking for, here. – Lightness Races in Orbit Feb 04 '13 at 08:08

6 Answers6

1

When window.onload ends, a is destroyed...

That assumption is wrong. Whenever you create functions within another function, those inner functions block the garbage collector from cleaning the scope of the outer function.

Recommended reading: http://www.ibm.com/developerworks/web/library/wa-memleak/

user123444555621
  • 148,182
  • 27
  • 114
  • 126
0

This is know as "Closure". In short, it means "a function has access to all variables in the scope in which it is defined".

In your example, the two handlers are defined inside the window.onload function, so it can access a, which is also in that scope.

And yes, the interpreter keep all closures in memory. (afaik)
I am not a professional programmer so I have not much authority. But I usually do this to avoid globals.

Closure on MDN

TwiNight
  • 1,852
  • 1
  • 17
  • 27
0

This is not a full answer to your question, but if it helps... object lifetime in Javascript is generally controlled via reference counting.

The language doesn't actually have a concept of block scope (though it does enjoy function scope). Objects are automatically cleaned-up by the background GC only when no references remain. Thus, the behaviour of your object a is sort of inherently "safe": one reference is dropped when the function scope ends, but another remains.

A more detailed answer would have to intricately explore a particular Javascript engine's implementation, likely to a detail greater than we have time or space for here.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
0

Functions or references to them in a variable in javascript are a type of object and just like regular objects, functions or variables holding references to them are not garbage collected until there are no references to them. In your particular case, you created a couple references to a() that last longer than the .onload() handler. So therefore, the variable a lasts much longer than the function too. This concept is known as a "closure".

If you search for the term "closures in javascript" in Google, you will find many helpful articles on the topic such as this one.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
0

Does the interpreter keep a hidden reference to the function in the background, or does the interpreter somehow inline the function?

This can not be answered globally for all javascript engines. But the parser will most likely have to keep a reference to your function a for both the anonymous functions you define on document.onclick and document.onkeyup. So a is not destroyed right away, it is only inaccessible through the restrictions of the javascript variable scope.

This is why closures can lead to memory leaks, because it is hard for the engine to actually dereference a properly. (which was a problem with the IE engine and still is when not handled carefully). And since you can not dereference a manually, because you have no access to the variable, there are no quick fixes to memory leaks arising from this type of pattern.

Your example is also not a closure, since it does not return a function, but it deals with the same kind of variable scope problems, since it references a local variable a inside functions not sharing the same scope (document.onclick and document.onkeyup).

I highly suspect that no engine will try to inline the function a, since that would unnecessarily duplicate the function object. It is most likely kept with a pointer and the mentioned reference count to be allowed to be destroyed easily once the reference count is down to 0 (in your example, when document.onclick and document.onkeyup are dereferenced (set to null or undefined).

Is this type of code to avoid a global variable efficient?

It is always good to avoid global variables, so in general: yes, it is an efficient way to avoid global variables. Every good engine should also destroy a once document.onclick and document.onkeyup are dereferenced.

Community
  • 1
  • 1
Beat Richartz
  • 9,474
  • 1
  • 33
  • 50
  • So basically `a` remains a hidden _quasi-global_ function, and there is probably very little practical difference to just declaring it explicitly global, other than avoiding an additional variable in the global scope, correct? –  Feb 04 '13 at 08:26
  • @pdknsk Not really - since functions defined on document are not global (in browser javascript, window is the global object), `a` never even touches the global scope. There is a big difference between a globally defined `a` and a reference to `a` kept in some function bodies, the main difference is that a globally defined `a` is accessible (and overwritable, which is the bad part) everywhere, where `a` in your example is not available anywhere besides inside the function body assigned to `window.onload`. – Beat Richartz Feb 04 '13 at 08:36
  • Thanks for the extended explanation. –  Feb 04 '13 at 08:39
0

A scope or context object is automatically created by JavaScript the moment you declare the first function inside the window.onload handler; this scope object preserves the variable a, effectively making it exclusive to both of your anonymous functions.

This technique is often used for information hiding and to prevent having to create global variables. Once the onload code has run, no other code has access to a.

Ja͢ck
  • 170,779
  • 38
  • 263
  • 309