1

I've read many questions on closures and JavaScript on SO, but I can't find information about what happens to a function when it gets closured in. Usually the examples are string literals or simple objects. See the example below. When you closure in a function, the original function is preserved even if you change it later on.

What technically happens to the function preserved in a closure? How is it stored in memory? How is it preserved?

See the following code as an example:

var makeFunc = function () {
  var fn = document.getElementById;  //Preserving this, I will change it later

  function getOriginal() {
    return fn;  //Closure it in
  }

  return getOriginal;
};

var myFunc = makeFunc();
var oldGetElementById = myFunc();  //Get my preserved function

document.getElementById = function () {  //Change the original function
  return "foo"
};

console.log(oldGetElementById.call(document, "myDiv"));  //Calls the original!
console.log(document.getElementById("myDiv"));   //Returns "foo"
Josh Hibschman
  • 3,148
  • 1
  • 25
  • 27
  • The type of the variable shouldn't matter; closures capture state at the time the closure is created. There's a reference to the function that you keep in the closure. You then set the original to a *new* function reference; there's no reason the closure should do anything different than it does for a string. – Dave Newton Jun 03 '15 at 19:57
  • You're not changing your original function anywhere. – Etheryte Jun 03 '15 at 19:58
  • @nit see //Change the original function – Josh Hibschman Jun 03 '15 at 19:59
  • @DaveNewton yes, but how does it capture state? How is the original function's state stored? – Josh Hibschman Jun 03 '15 at 20:00
  • @y3sh I read your code, you're not changing your original function. – Etheryte Jun 03 '15 at 20:02
  • 1
    @y3sh It's a function reference--a reference like any other reference. The function still exists as it did originally because something has a reference to it. Are you asking how JS is implemented at the lowest levels? – Dave Newton Jun 03 '15 at 20:02
  • @Nit The OP is referring to redefining `getElementById`. (AFAICT) – Dave Newton Jun 03 '15 at 20:03
  • @DaveNewton the answer i'm looking for should contain terms like activation records, heap, pointers, etc -- so yes, low level – Josh Hibschman Jun 03 '15 at 20:07
  • 1
    @y3sh Then I'd suggest starting poking at the implementation of your choice and see how it stores functions--but it's no different for the value of an enclosed function than anything else; it's a reference. As soon as you know how *any* function works in the JSVM you'll have the answer to your question. – Dave Newton Jun 03 '15 at 20:09
  • I think this might be what I'm looking for: http://stackoverflow.com/a/26063201/786389 – Josh Hibschman Jun 03 '15 at 20:14
  • There are 89 answers to http://stackoverflow.com/questions/111102/how-do-javascript-closures-work?rq=1 Are you sure that none of them address your question? – Barmar Jun 03 '15 at 20:39
  • You might want to get the textbook "Structure and Interpretation of Computer Programs". It goes through the exercise of implementing a language with closures (Scheme), and explains in detail how they work. – Barmar Jun 03 '15 at 20:43
  • 1
    A function is just an object like the number 3 or the string "hello". When you do `var x = 3` then do `x = 5`, do you consider it as changing the number 3? Or do you simply take it as changing the value of `x` to 5? The same happens here, the function is pointed to by two variables, then you change the value of one of the variables. The other variable's value isn't affected so it's still pointing to the old function. This has nothing to do with the stack frame (activation record) or closure. It's just the way variables work. – slebetman Jun 03 '15 at 21:05
  • You can for example simplify this example further by getting rid of the closure and just see what happens when you use a global variable `fn`. – slebetman Jun 03 '15 at 21:06
  • @y3sh ... Perhaps, although it's no different from what I said, and is an *example* implementation, not necessarily how a specific JSVM actually works. I'm not complaining, I'm just not sure where the disconnect is. *@slebetman* said essentially the same thing. – Dave Newton Jun 04 '15 at 13:26

1 Answers1

1

Thanks for the comments and discussion. After your recommendations, I found the following.

What technically happens to the function preserved in a closure?

Functions as objects are treated no differently than any other simple object as closured variables (such as a string or object).

How is it stored in memory? How is it preserved?

To answer this, I had to dig through some texts on programming languages. John C. Mitchell's Concepts in Programming Languages explains that closured variables usually end up in the program heap.

Therefore, the variables defined in nesting subprograms may need lifetimes that are of the entire program, rather than just the time during which the subprogram in which they were defined is active. A variable whose lifetime is that of the whole program is said to have unlimited extent. This usually means they must be heap-dynamic, rather than stack-dynamic.

And more specific to JavaScript runtimes, Dmitry Soshnikov describes

As to implementations, for storing local variables after the context is destroyed, the stack-based implementation is not fit any more (because it contradicts the definition of stack-based structure). Therefore in this case closured data of the parent context are saved in the dynamic memory allocation (in the “heap”, i.e. heap-based implementations), with using a garbage collector (GC) and references counting. Such systems are less effective by speed than stack-based systems. However, implementations may always optimize it: at parsing stage to find out, whether free variables are used in function, and depending on this decide — to place the data in the stack or in the “heap”.

Further, Dmitry shows a varied implementation of the parent scope in function closures:

As we mentioned, for optimization purpose, when a function does not use free variables, implementations may not to save a parent scope chain. However, in ECMA-262-3 specification nothing is said about it; therefore, formally (and by the technical algorithm) — all functions save scope chain in the [[Scope]] property at creation moment.

Some implementations allow access to the closured scope directly. For example in Rhino, the [[Scope]] property of a function corresponds to a non-standard property __parent__.

Josh Hibschman
  • 3,148
  • 1
  • 25
  • 27