1

The following function returns an object. It's taken from a MDN document. This object that is returned has properties that are functions, which reference the "private" function changeBy().

I'm pretty sure that the only way an increment() call will resolve the changeBy() function call is to have access to the scope chain - the scope of the enclosing/parent function.

Q: Is the scope chain property set on the increment() function where it is declared, even though it is declared inside an object, and has not been invoked at that point?

Note I'm being pointed to How do JavaScript closures work? as a possible duplicate.

The magic is that in JavaScript a function reference also has a secret reference to the closure it was created in — similar to how delegates are a method pointer plus a secret reference to an object

Q: The secret bit is what I'm asking about, which is not explained in the answer given in there. Where is this reference stored?

var makeCounter = function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    value: function() {
      return privateCounter;
    }
  }  
};

var counter1 = makeCounter();
alert(counter1.value()); /* Alerts 0 */
counter1.increment();
alert(counter1.value()); /* Alerts 1 */
Community
  • 1
  • 1
Drenai
  • 11,315
  • 9
  • 48
  • 82
  • At the point that the result object created, `changeBy()` is in scope, so even though it's out of scope where you call `increment()`, `counter1` has its own scope to `changeBy()` (if that makes sense). – Reinstate Monica Cellio Dec 06 '16 at 12:29
  • 3
    Yes: the fact that the function is declared in an object is irrelevant. – Maurice Perry Dec 06 '16 at 12:30
  • @Brian, reference to _changeBy_, saved in closure for function assigned to increment field – Grundy Dec 06 '16 at 12:36
  • I'm pretty sure there is no direct reference to changeBy saved. Just the parent scope reference is applied to increment() function, and the changeBy location is only resolved when increment is called. Just need to know how/when that reference is applied to increment(), and what rules govern that i.e. in the case where its declared inside an object, or just declared as a function – Drenai Dec 06 '16 at 12:38
  • 1
    Possible duplicate of [How do JavaScript closures work?](http://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – Grundy Dec 06 '16 at 12:41
  • increment method refers to makeCounter's changeBy thus the makeCounter scope is not garbage collected after the function exits and remains accessible. – webduvet Dec 06 '16 at 12:41
  • 1
    here nothing specific. Simple closures, so common answer about how closures work should help – Grundy Dec 06 '16 at 12:44
  • @webduvet From reading the specs, I do not think there is a reference to changeBy function at all. Just a reference to the enclosing parent scope. We might think of it as a saved reference to changeBy(), but I don't think that is how the VM resolves it. – Drenai Dec 06 '16 at 12:44
  • 1
    I concur this is a very standard run-of-the-mill closure. I'm not sure what makes your question special. Are you interested in how the engine implements it? In how the spec defines it? – deceze Dec 06 '16 at 12:48
  • I updated the question, with refernece to the possible duplicate. I think what I'm looking for is pretty specific. If I'm wrong, I'm wrong – Drenai Dec 06 '16 at 12:52
  • 3
    *"Where is this reference stored."* – Internally in the Javascript engine. It's not accessible to userland code. – deceze Dec 06 '16 at 12:58
  • I found the info I needed in the ECMAScript 5.1 specs and updated the question with that info – Drenai Dec 06 '16 at 16:25
  • 1
    @Brian If you found what you're looking for you should post it as an answer and accept it. If you update your question to contain the answer your question becomes unanswerable which doesn't fit the SO format very well. – Paul Dec 06 '16 at 16:34

2 Answers2

1

I found the answer to the level of detail I was looking for in the ECMAScript specs. This is pretty in-depth, but it explains the function creation/initialization process, and the function initialization process when created within an Object Literal

ECMAScript 5.1 spec

Function Being Created

When a function is being created, as opposed to called, step 9 covers the scope property: Where the Lexical Environment is specified by [[Scope]], and F is the new Function, and the Scope is the current functions scope/lexical environment:

9: Set the [[Scope]] internal property of F to the value of Scope

Entering Function Code 10.4.3

  1. Let localEnv be the result of calling NewDeclarativeEnvironment passing the value of the [[Scope]] internal property of F as the argument.
  2. Set the LexicalEnvironment to localEnv.

Function Created in Object Literal 11.1.5

The part I was interested in is "Pass in the LexicalEnvironment of the running execution context as the Scope"

  1. Let closure be the result of creating a new Function object as specified in 13.2 with an empty parameter list and body specified by FunctionBody. Pass in the LexicalEnvironment of the running execution context as the Scope. Pass in true as the Strict flag if the PropertyAssignment is contained in strict code or if its FunctionBody is strict code.

ECMAScript 2016

Set the [[Environment]] internal slot of F to the value of Scope.

Drenai
  • 11,315
  • 9
  • 48
  • 82
0

Is the scope chain property set on the increment() function where it is declared, even though it is declared inside an object, and has not been invoked at that point?

Yes.

increment is associated with the lexical environment in which it occurs, and has access to all variables in that environment, even after being "released into the wild" by being returned, whether it's returned directly, or as you are doing, as a value in an object being returned.

The secret bit is what I'm asking about, which is not explained in the answer given in there. Where is this reference stored?

It's written on a post-in stuck to the refrigerator door. No, seriously, it's stored inside the engine as part of its internal data structures while the JS is being parsed and interpreted.

By the way, you're misusing the term "closure". "Closure" does not simply mean "function", anonymous or otherwise. It refers to a particular interaction and behavior between variables in an outside scope (which are "closed over") and functions defined within that scope which reference them ("close over them").

  • Ha. No prob. Do you know what property on the increment function gets set? Is the the [[scope]] value we see when debugging? – Drenai Dec 06 '16 at 13:00
  • 1
    @Brian, yes, you can see closures in chrome devtools in `[[Scopes]]` field, by still no way get it from your js code – Grundy Dec 06 '16 at 13:17
  • FYI on the term scope chain - I've seen it a number of times in the MDN reference guide. Scope objects form a chain called the scope chain, similar to the prototype chain used by JavaScript's object system. https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript – Drenai Dec 06 '16 at 14:29