0

I'd like to understand the debugging content during the execution of the following code:

var z = 2;

var SQUAREPLUSOTHER = x => y => ((x*x) + y + z);

var x = 3;

console.log("SQUAREPLUSOTHER", SQUAREPLUSOTHER);

var squareoftwoplusother = (SQUAREPLUSOTHER)(x);

x = 4;
z = 4;
var result = squareoftwoplusother(5);
console.log("result", result);

Now.... At the call of:

console.log("SQUAREPLUSOTHER", SQUAREPLUSOTHER);

the debug shows clearly:

squareoftwoplusother: undefined
SQUAREPLUSOTHER: x=>...
x: 3
z: 2

at the following call of:

var SQUAREPLUSOTHER = x => y => ((x*x) + y + z);

the debug shows:

Local:
  x: 3
Closure
  z: 2

at the following call of:

x = 4;
z = 4;

the debug shows:

squareoftwoplusother: y=>...
SQUAREPLUSOTHER: x=>...
x: 4
z: 4

at the following call of:

var result = squareoftwoplusother(5);

the debug shows:

result: 18
squareoftwoplusother: y=>...
SQUAREPLUSOTHER: x=>...
Local:
  x: 5
Closure
  x: 3
Closure
  z: 4

and at the final calls the debug shows:

result: 18
squareoftwoplusother: y=>...
SQUAREPLUSOTHER: x=>...
x: 4
z: 4

now the questions: How many "Closures"? They belongs to? (i.e. how to explain...)

Local:
  x: 5
Closure
  x: 3
Closure
  z: 4

How the scope of the variables is managed in javascript? How to have a "definitive" idea in terms of "context" or "whatever it be" about the mess of closure :-)?

thanks in advance

Ed

2
  • Question is unclear. Is it "How many closures are created in this code?" If so, which part is unclear, you seem to have debugged it and understood that different closures are created. Commented Oct 25, 2018 at 12:57
  • otherwise, why the debug (by the way nodejs debug) should place "two" Closure x: 3 Closure z: 4 ? anyway my question is more related to understand, for example, the relation between the scope of the variable and the closure..thanks again Commented Oct 25, 2018 at 13:01

2 Answers 2

0

Every time a function is called, a local scope is created for that function. If there is still a reference to that local scope after the function returns, then a closure is created. Once the reference is gone, the closure is also garbage collected.

If you add breakpoints to the first line of every function, you will see that scopes are created that may later become closures.

A great explanation is given here http://dmitrysoshnikov.com/ecmascript/javascript-the-core/#activation-object

I'll add some braces to your code to make that easier and I'll add self calling function to add a level of closures.

(() => {
  var z = 2;

  var SQUAREPLUSOTHER = (x) => {
    debugger;
    return (y) => {
      debugger;
      return (x * x) + y + z;
    }
  };

  var x = 3;

  console.log("SQUAREPLUSOTHER", SQUAREPLUSOTHER);

  var squareoftwoplusother = (SQUAREPLUSOTHER)(x);

  x = 4;
  z = 4;
  var result = squareoftwoplusother(5);
  console.log("result", result);
  debugger
})()

The screenshots below are from Chrome DevTools which minimizes the closures, that is, it only maintains references to what is needed. Back in the days, the entire closure was always available and you could prove it because it showed up in the closures pane of debuggers. See Javascript closures performance for further details

First breakpoint

Second Breakpoint

End of code

Sign up to request clarification or add additional context in comments.

Comments

0

Scope

There are just three different scopes in your code. One is the global scope all variables you declare in and the other two are here:

 var SQUAREPLUSOTHER = x => y => ((x*x) + y + z);

There are two function scopes, one containing the variable x and the other function scope containing the variable y. It might be easier to see if you replace the arrow function with functions:

 // global scope
 function SQUAREPLUSOTHER(x) {
   // function scope containing x
   return function(y) {
     // function scope containing y
     return (x*x) + y + z;
   };
 }

How scoping works is actually quite simple:

  • Every { starts a new scope and its counter } closes it, variables declared inside it with let and const (or var but thats slightly more complicated) are part of the scope. If it is the scope of a function, the parameters (e.g. x and y) are part of that scope.

  • From the code, you can access the all variables that are in the current scope or in its parent scope, if there are multiple with the same name you get the most inner one. Therefore x inside of the SQUAREPLUSOTHER function refers to the variable of the SQUAREPLUSOTHER scope, while for code outside of it x is the global variable and the functions variable can't be accessed.

The Scope of a variable does not change at runtime, you can always directly see which scope a variable belongs tp by looking at the surrounding { .. }.

Now different variables in different scopes have to hold values at runtime, thats where we get to:

the environment record

When you call a function, the JavaScript engine creates a new "EnvironmentRecord" (which is like an internal object) that contains all the variables of the function you call, e.g. in this case:

  function test(a) {
    let b;
  }

Then if you call that function (test(1)) a new environment record gets created that contains a and b. Now the code inside the function gets run, and every variable is looked up in it. If there are two functions nested into another, calling the inner function will create an environment record that holds a reference to the outer one:

 function test(a) {
   function test2(b) {
   }

   test2(5);
 }

Now calling test(1) will create an record where a is 1. If the engine then executes the second call (test2(5)) it creates another record containing b being 5, and that holds a reference to the record containing a. Now if you use a inside test2, the engine will look it up in the current environment record, won't find it, and then look it up in the parent where it finds a being 1.

closure

Usually those records get deleted when the execution reaches the }, however if there is another record that got the current record as a parent, it won't get deleted. It will exist until all child records got deleted, then it will also remove the parent. This behaviour (variables live longer because they can be accessed from an inner functions body) is called a closure.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.