Function scope
Lexical scope
After assignment to a variable (or constant), a value is bound to a name, to an identifier. Somewhere else in the code this identifier can be used to reference its assigned value. But this only holds for certain parts of the code. Parts of the code where an identifier can be used to reference its assigned value is called the scope of that identifier, or "the scope of that variable".
A function declaration or function expression creates a binding of an identifier and a function value.
"use strict";
function functionScope() {
  function f() { console.log("This function's scope is function scope") }
}
f = "reassignedValue" // ReferenceError: assignment to undeclared variable f
                      // variable f is not in global scope
if (true) {
  const f = function() { console.log("This function's scope is block scope") }
}
f(); // ReferenceError: f is not defined
     // constant f is not in global scope
"use strict";
{
let add;
}
add = (a, b) => a + b; // ReferenceError: assignment to undeclared variable add
                       // variable add not in global scope
BTW. In non-strict mode there would not have been errors in the first and last examples. Assigning to an undeclared variable would have created an implicit global and given the variable global scope.
Note that, in common usage, when we speak of the "scope of a variable or function", "scope" refers to an identifier, rather than to a value. Assigning a (new) value to a variable or constant does not create or change any scope. Lexical scope is concerned with the accessibility of identifiers, not with the values they reference. In the next example the same object value is assigned to two different constants, each with its own scope.
const someVar = { a: 2 }; // constant in global scope
function f() {
  const someLocalVar = someVar; // constant in function scope
  console.log(someLocalVar === someVar);
}
f();                       // logs: true
                           // both reference the same object value
console.log(someVar);      // Logs: Object { a: 2 }
                           // someVar in global scope
console.log(someLocalVar); // Uncaught ReferenceError: someLocalVar is not defined
                           // someLocalVar not in global scope
If scope is depending on where the variable or function is declared in the code, the scope is called lexical scope, also called static scope as opposed to dynamic scope (which does not exist in JS). In JavaScript, the scope is determined by the code area (a block, a function) in which declaration takes place.
In JavaScript the following scopes exist:
- Global scope: The default scope for all code (except code running in module mode). The global scope is the scope that contains, and is accessible by all other scopes. In client-side JavaScript, the global scope is generally the web page.
 - Function scope: The code within a function.
 - 
	Block scope: The code within a block statement (enclosed in a pair of curly brackets).
	Only 
let-variables andconst-constants declare block scope, as we have seen. In strict mode function declarations declare block scope, in non-strict mode function declarations in blocks declare inconsistently across user agents. Function expressions (usingletorconst) declare block scope, both in strict mode and in non-strict mode. 
In JavaScript there is also module scope, i.e. the scope for code running in module mode. Modules will be explained later in this tutorial.
Levels or layers of scopes can be created, depending on where the variable or function is declared in the code. Child scopes have access to parent scopes, but not vice versa.
So, the lexical scope of a variable or function is one of the above scopes, including all its child scopes, in which the variable or function is declared.
Functions can only be referenced to (e.g. invoked) in their lexical scope, which is the function scope or global scope in which the function is declared, including all its child scopes. Likewise, variables can only be referenced to in their lexical scope, including all its child scopes.
"use strict";
// Variables and functions declared in global scope are available in the entire application. 
const addend1 = 2;
const addend2 = 3;
function addTo() {
  return add();
  // function add is declared in the scope of function addTo
  function add() {
    return addend1 + addend2;
  }
}
console.log(addTo()); // logs: 5
add(); // ReferenceError: add is not defined // outside addTo, add is out of scope
In the example above we can see that with function declarations both the variable (or constant) and the assigned function value are hoisted to the top of their scope. Within its scope you can call a function before the function is declared.
Function expressions behave as any other assignment to a variable (or constant).
In a previous chapter we learned that with a var declaration the variable is hoisted to the top of its scope, but not its explicitly assigned value.
With a let or const declaration the variable or constant is in a temporal dead zone (TDZ),
from the start of scope until the declaration statement in the code.
Accessing the variable or constant within the TDZ results in a ReferenceError:
add(2, 3); // ReferenceError: can't access lexical declaration 'add' before initialization
const add = function(a, b) {
  return a + b;
}
Function declarations declare block scope in strict mode. In non-strict mode function declarations in blocks declare inconsistently across user agents.
"use strict";
if (true) {
  function f() { console.log("This function's scope is block scope") }
}
f(); // ReferenceError: f is not defined
     // In non-strict mode this might work
Functions can only be invoked within their lexical scope, with the exception of Immediately Invoked Function Expressions. They are not assigned to a variable or constant, so they cannot be invoked in any scope (except, of course, the one time they get self-invoked).
(function () {
  console.log("Hello World!"); // logs: "Hello World!"
})();
Scope of a returned function
Let's reconsider one of the examples above:
const addend1 = 2;
const addend2 = 3;
function addTo() {
  return add();
  function add() {
    return addend1 + addend2;
  }
}
add(); // ReferenceError: add is not defined // outside addTo, add is out of scope
And let's make a few changes. We make
addTo() return the function add as opposed to returning the result of the execution of add.
Inner function add is not executed within outer function addTo(), the outer function only returns an instance of the inner function.
Then we declare a global constant and assign to it the return value (the inner function) of addTo().
const addend1 = 2;
const addend2 = 3;
function addTo() {
  return add; // Now it returns an entire function instead of only the return value of add()
  function add() {
    return addend1 + addend2;
  }
}
const addClosure = addTo();
console.log(addClosure()); // logs: 5
console.log(addClosure.name); // logs: "add"
                              // constant addClosure was assigned a function named "add"
console.log(addTo() === addTo()); // logs: false
In this example addClosure() invokes its assigned function, which is an instance of add, but now this does not throw an error, although
add seems outside its scope as it was in the first example.
JavaScript is a language where all functions are
first-class citizens, meaning that
functions can be passed as arguments to other functions and functions can be returned as values from other functions.
In the example above, in const addClosure = addTo();, constant addClosure is declared in global scope,
and assigned a function named add via addTo() because addTo() returns an instance of function add.
The lexical scope of addClosure, bound to an instance of the inner function add, is now global scope.
In the next line in the above example addClosure() invokes the function within this scope.
Note that this function cannot be invoked directly by add() in global scope.
There is no variable or constant named "add" declared in global scope.
A function value named "add" is assigned to constant addClosure with global scope.
We might as well return an anonymous function expression:
const addend1 = 2;
const addend2 = 3;
function addTo() {
  return () => addend1 + addend2; // inner function is defined by an anonymous function expression
}
const addClosure = addTo();
console.log(addClosure()); // logs: 5
console.log(addClosure.name); // logs: "" // empty string
We can also directly self-invoke the returned inner function:
const addend1 = 2;
const addend2 = 3;
function addTo() {
  return () => addend1 + addend2; // inner function is defined by an anonymous function expression
}
addTo()(); // returns: 5
BTW. Note that this acts as an Immediately Invoked Function Expression. The inner function is not assigned to a variable or constant in global scope.
Lexical environment
A concept that is closely related to lexical scope is lexical environment. while lexical scope refers to the regions of your code where a particular identifier is accessible (at write time), the concept of lexical environment is a description of the internal mechanism that JavaScript uses to manage variables and their current values, based upon the lexical scope, during execution of the program (at runtime). You can think of it as lexical scope being the design and lexical environment being the internal runtime mechanism built from that design.
A lexical environment is generally described as a hidden object that belongs to a (running) code block or function. Instances of all in-scope variables and parameters (according to lexical scope) and their current values are stored as the properties of this object (this is called the environment record). And in addition this object contains a reference to the outer lexical environment, the parent lexical environment.
Because of the references to outer lexical environments, a running code block or function is associated to a chain of lexical environments. Also the script as a whole has a lexical environment, the global lexical environment. This global lexical environment is the last parent lexical environment and does not have a reference to an outer lexical environment. When searching for a variable, JavaScript goes through this chain, from most inner lexical environment to each outer one until the variable is found, or until the most outer one, the global lexical environment, is reached.
The lexical environment chain, as well as the individual lexical environments, constantly chance as the program execution progresses.
At the beginning of each function call, a new lexical environment is created that stores instances of the function's local variables and the call's parameters (all directly accessible variables and parameters according to the lexical scope) and their current values. What is stored in this lexical environment is called the (functional) execution context.
A function call stores the lexical environment the function was defined in! In the example below, the function call stores instances of all directly in-scope variables and parameters in the lexical environment the function (not the identifier) was defined in (which is the code block environment).
const returnValue = "globalVar";
let myFunc;
{
  const returnValue = "localVar";
  myFunc = function () {
    return returnValue;
  };
}
console.log(myFunc()); // logs: "localVar"
Lexical environment chain:
lexical environment of myFunc() call ------------------------------------- returnValue: "localVar" ↳ global lexical environment -------------------------- returnValue: "globalVar", myFunc: function
Next example shows the lexical environment chain of a call of a returned function.
function addTo(addend1) {
  return add;
  function add(addend2) {
    return addend1 + addend2;
  }
}
const addTo2 = addTo(2);
console.log(addTo2(3)); // logs: 5 // 2 + 3
Lexical environment chain:
lexical environment of addTo2(3) call
-------------------------------------
addend2: 3
↳ lexical environment of addTo(2) call
  ------------------------------------
  addend1: 2,
  add: function
  ↳ global lexical environment
    --------------------------
    addTo: function,
    addTo2: function
Closures
The combination of a function and an associated lexical environment (the whole chain) is called a closure.
Let's expand the previous example by adding a addTo(3) call.
function addTo(addend1) {
  return add;
  function add(addend2) {
    return addend1 + addend2;
  }
}
const addTo2 = addTo(2);
const addTo3 = addTo(3);
console.log(addTo2(3)); // logs: 5 // 2 + 3
console.log(addTo2(4)); // logs: 6 // 2 + 4
console.log(addTo3(3)); // logs: 6 // 3 + 3
console.log(addTo3(4)); // logs: 7 // 3 + 4
console.log( addTo(2)(3) ); // logs: 5
In the example above, the addTo(2) call and the addTo(3) call both create their own lexical environment.
They both return an instance of the same function, but each attached to a different lexical environment, and therefore they have a different scope. 
Each lexical environment contains instances of all the in-scope variables and parameters and their values at the time of the specific call.
In the closure created by const addTo2 = addTo(2), addend1 has value 2,
which is preserved for every time this function is invoked again by referencing addTo2.
Statement const addTo3 = addTo(3) assigns an instance of the same inner function add, but with a different lexical environment.
This closure preserves the value 3 for addend1 for every time this function is invoked again.
So with closures you can turn a function with returning inner function into a function factory. In the above example, from one function new functions that do different things were created, one that adds its argument to 2, and one that adds to 3. They do different things because the function operates on different sets of data (different lexical environments). Note that the function above could have been written a little shorter:
function addTo(addend1) {
  return function (addend2) {
    return addend1 + addend2;
  }
}
As another example, let's look back at the original example, but now we declare constants addend1 and addend2 in function scope instead of global scope: 
function addTo() {
  const addend1 = 2;
  const addend2 = 3;
  return function() {
    return addend1 + addend2;
  }
}
const addClosure = addTo();
console.log(addClosure()); // logs: 5
The inner function has access to constants addend1 and addend2 when addClosure()
calls an instance of the inner function in global scope, which is outside the scope of both constants.
This is possible because calling function addTo() created a closure that stored instances of constant addend1 and constant addend2
and their current values.
Keep in mind that a closure stores copies of all variables and parameters that were in-scope, and their values, at the time the closure was created.
In the next example the closure is created in the last line. At that time the two variables have values 4 and 5
and not 2 and 3.
let addend1 = 2;
let addend2 = 3;
function addOuter() {
  return function add() {
    return addend1 + addend2;
  }
}
addend1 = 4;
addend2 = 5;
console.log(addOuter()()); // logs: 9
A few more examples:
function outer(x) {
  if (Math.random() > 0.5) {
    const y = x + 1;
    return () => console.log(x+", "+y);
  } else {
    const y = x - 1;
    return () => console.log(x+", "+y);  
  }
}
outer(3)();
// logs: 3 4
// or logs: 3 2
// Constant y is not in scope of the returned inner function
// because it is in a block scope a level deeper than
// the scope the inner function is in.
function outer(x) {
  {
    const y = x + 1;
  }
  return () => console.log(x+", "+y); // ReferenceError: y is not defined 
}
outer(3)();
Global variables
Copies of accessible variables, constants and parameters are stored in a lexical environment. They are unique to that lexical environment. However, instances of in-scope variables and constant in the global lexical environment are not stored! Only a reference to a global variable is stored. Global variables are properties of the global object. By definition, they are shared throughout the entire JavaScript realm. There exists only one instance of a global variable.
let globalVar = { a: 0 }; // This is a global variable
function createLogger() {
    let localVar = { a: 0 }; // This is a closure-specific variable
    return function() {
        localVar.a++;
        globalVar.a++;
        console.log(`localVar.a: ${localVar.a}, globalVar.a: ${globalVar.a}`);
    };
}
const loggerA = createLogger();
const loggerB = createLogger();
loggerA(); // logs: "localVar.a: 1, globalVar.a: 1"
loggerB(); // logs: "localVar.a: 1, globalVar.a: 2"
In the example above the loggerA() call mutated the global object by adding 1 to globalVar.a.
This change is also visible in the loggerB closure! The loggerB() call added 1 to the globalVar.a property of the shared global object,
already incremented by 1 in the previous loggerA() call, resulting in the new value of 2.
However, each closure has its own unique instance of localVar.
Closure chain
As explained before, a lexical environment contains a reference to its direct parent lexical environment. This results in a chain of lexical environments. If an outer function is nested in yet another function, the closures will capture the execution context of the most inner function, the outer function, the outer's outer function up to the global environment.
const e = 10;
function sum(a) {
  return function (b) {
    return function (c) {
      // outer functions scope
      return function (d) {
        // local inner scope
        return a + b + c + d + e;
      };
    };
  };
}
console.log(sum(1)(2)(3)(4)); // 20
Closures and loops
A common problem occurs when outer functions, that return an inner function, are created in a loop and the loop counter variable is outside the loop.
const outerFunctions = [];
let i = 0;
for (; i < 3; i++) {
  outerFunctions[i] = function () { return () => console.log(i) };
}
outerFunctions[0]()(); // logs: 3
outerFunctions[1]()(); // logs: 3
outerFunctions[2]()(); // logs: 3
In this example one may expect that the output will be 0 ,1, 2 instead of 3 ,3, 3.
However, in the for loop, outer functions are just assigned into the global array.
No inner or outer functions are called yet.
At the time functions are called, the loop has finished and i has its final value 3.
The same thing happens if you declare i using the var keyword inside the loop: for (var i = 0; i < 3; i++).
A var variable does not declare block scope; it declares global scope, just like with the previous let declaration.
But what happens if you use a let loop counter variable inside the loop?
const outerFunctions = [];
for (let i = 0; i < 3; i++) {
  outerFunctions[i] = function () { return () => console.log(i) };
}
outerFunctions[0]()(); // logs: 0
outerFunctions[1]()(); // logs: 1
outerFunctions[2]()(); // logs: 2
Now it works as desired. Now each iteration creates a
new binding of i, scoped to that code block.
Each outer function call stores the code block lexical environment, with its own distinct i, the function was defined in.
Each call closes over its own copy of i with its own distinct value.
With i declared global scope, like in the initial examples, the same single i is incremented.
All closures created inside the loop captured the same i binding.
Another way is to create the closures in the loop and pass i with a successive value each iteration to an outer function.
Each outer function is now invoked while storing a current (and not the final) value of the global variable i. 
const innerFunctions = [];
let i = 0;
for (; i < 3; i++) {
  // closures are created:
  innerFunctions[i] = createClosure(i);
}
function createClosure(i) { return () => console.log(i) }
// inner functions are invoked
innerFunctions[0](); // logs: 0
innerFunctions[1](); // logs: 1
innerFunctions[2](); // logs: 2
A more practical and common example of this pitfall is shown in the next script
(notice the var-variable i, which declares global scope!):
<button>Button 1</button>
<button>Button 2</button>
<button>Button 3</button>
<script>
const buttons = document.getElementsByTagName('button');
for (var i = 0; i < buttons.length; i++) {
  buttons[i].addEventListener("click", () => { alert(`You clicked button ${i+1}`) });
}
</script>
Clicking any of the three buttons alerts "You clicked button 4", which was clearly not the intention of this script.
The outer functions (instances of the arrow function) are stored in constant buttons and will be invoked when a button gets clicked on, which creates a closure.
The inner functions, as part of the closures, are the alert methods (which are functions).
We know now that this script can easily be fixed by changing var into let
or, more cumbersome, by creating the (in this case extra) closures inside the loop.
<button>Button 1</button>
<button>Button 2</button>
<button>Button 3</button>
<script>
const buttons = document.getElementsByTagName('button');
for (var i = 0; i < buttons.length; i++) {
  (function (i) {
    buttons[i].addEventListener("click", () => { alert(`You clicked button ${i+1}`) });
  })(i);
}
</script>
Private data with closures
The outer function in the next example returns an object which has three methods (which are functions).
The three methods share a single lexical environment which contains two private items:
a variable called privateValue, and a function called multBy.
Outside function doubler,
the private variable privateValue and private function multBy
are only indirectly accessible by using the three returned public methods which are closures.
const doubler = function () {
  let privateValue = 2;
  function multBy(factor) {
    privateValue = Math.round(privateValue * factor);
  }
  return {
    doubleIt: function() {
      multBy(2);
    },
    halfIt: function() {
      multBy(0.5);
    },
    value: function() {
      return privateValue;
    },
  };
};
const doubler1 = doubler();
const doubler2 = doubler();
console.log(doubler1.value()); // logs: 2
doubler1.doubleIt();
doubler1.doubleIt();
console.log(doubler1.value()); // logs: 8
doubler1.halfIt();
console.log(doubler1.value()); // logs: 4
console.log(doubler2.value()); // logs: 2
Both constants doubler1 and doubler2 are objects
with each an independent lexical environment for their three methods. The methods of doubler1 are in a different closure
then the methods of doubler2.
Changing the private variable value privateValue in one closure does not affect the value in the other closure.
JavaScript provides more ways to declare private data. More about this later in chapters about classes and object-oriented programming.
Performance
In the example above, closures in both doubler1 and doubler2 maintain their own lexical environment.
Each closure consumes memory and negatively affects processing speed.
Therefore, nested functions should be avoided if closures are not necessarily needed to perform a particular task.
You can clear a closure by assigning another value to the variable.
Then the closure is no longer accessible and will be removed from memory (garbage collection). 
function addTo(addend1) {
  return function (addend2) {
    return addend1 + addend2;
  }
}
let addTo2 = addTo(2); // lexical environment of this closure stays in memory
addTo2 = null; // The assigned function instance is no longer accessible.
               // This closure will be cleared from memory.
addTo(2)(3); // The returned function instance is no longer accessible after this call.
             // This closure will be cleared from memory.