When executing a function or script, the JavaScript interpreter creates a new context. Every script/function has a base context called global execution context. And every time we call a function, a new execution context is created and is put on top of the execution stack. The same pattern follows when you reach the nested function which calls another nested function. There are two scopes in JavaScript.
- Global Scope
- Local Scope
Global Scope
There is only one global scope throughout a JavaScript document. We can access and change variables in the global scope.
Local Scope
Variables defined inside a function are in the local scope. And they have a different scope for every call of that function. This means the same variable name can exist in other functions as well. This is because those variables are bound to that scope. Example:
Scope Chain
The scope chain helps to resolve variables. When a variable needs to resolve, JavaScript starts from the innermost level of the code and keeps jumping back to the parent scope until it finds the variable it’s looking for.
Lexical Scope
When we have a nested group of functions, the inner function has access to variables and other resources of the parent function. This means child functions are lexically bound to the execution context of their parents. The printMyName() function had access to name variable of findMyName() function. This will work only in one direction, you cannot access variables and other resources residing in the inner function from the parent function.
Lexical Environment
When the JavaScript engine creates a new execution context for a function, it creates a new lexical environment to store variables defined in that function during the execution phase. A lexical Environment is a data structure that holds an identifier-variable mapping. (here identifier refers to the name of variables/functions, and the variable is the reference to the actual object [including function type object] or primitive value). The lexical environment contains two components:
- Environment record: It is the actual place where the variable and function declarations are stored.
- Reference to the outer environment: It means it has access to its outer (parent) lexical environment.
let language = "JavaScript";
function a() {
const b = "Dart";
console.log("Inside function a");
}
a();
console.log("Global execution context");
When the JavaScript engine creates a new execution context for global, it creates a new lexical environment to store variables and functions defined in the scope. It looks like this:
globalLexicalEnvironment = {
environmentRecord: {
language : 'JavaScript',
a : "< reference to function object >"
}
outer: null
}
When the JavaScript engine creates a new execution context for function a()
, it creates a new lexical environment to store variables and functions defined in the scope. It looks like this:
functionLexicalEnvironment = {
environmentRecord: {
b : 'Dart',
}
outer: '<globalLexicalEnvironment>'
}
When the function completes the execution it may or may not be removed from the stack, depending on if that lexical environment is referred to by any other lexical environments in their outer lexical environment property.