What the GEC and FEC ?!
In the previous article, we learned about how the Macro and Micro tasks are scheduled in task queues for the non-blocking behaviour and how event loop prioritises Micro tasks over Macro tasks. We also learned that call stack is where all code/tasks are executed by storing the function calls in LIFO order. Today, we will go little deeper to understand how the function calls are executed within the call stack.
Execution Context
Execution context is an environment created by the JavaScript engine to execute the JS code. This context includes all the necessary information for the program to execute. It can be thought as a staging area where all the required objects are made available to perform the execution such as variables and functions. GCE and FEC are the two types of those contexts.
GEC: Global Execution Context
GEC is the first thing that is created in the script execution. It is the default or base execution context. All the variables and functions that are not inside any function are attached to the global object. In Node it is called global object and in browsers it is the Window object.
Before the code execution starts, variables that are declared with var are attached at the top of the global object initialised with 'undefined' value. Function declarations are attached along with the function definition. This means, var variables and functions can be accessed from anywhere in the code, even before their declaration. But the value of the variables remain undefined until their assignment. This is called Hoisting.
In the above code, the var1 is accessed and test function is called before their declaration. This doesn't give error like in the other programming languages. Because, they are hoisted in the execution context with undefined and function definition respectively. The output will look like this.
undefined
inside test
10
Technically, the execution context creates a Lexical environment to store the variables and functions. Block scoped variables (let and const) are added in a 'block lexical environment'. However, they are not hoisted like var. They are kept in a Temporal Dead Zone(TDZ) during the creation of the execution context, making them inaccessible before their declaration.
The code that is present in the global context is started to execute first. So, the GEC is the first one to be added in the call stack. When a function is invoked, a new execution context is created which is called the functional execution context.
领英推荐
FEC: Functional Execution Context
FEC is created when a function is invoked. This is just like the GEC but with the function's arguments, variables and functions inside that. Variables with var declarations and functions that are part of the current function are hoisted to the top of the functional context.
Here comes the fascinating part. The variables and functions belonging to the global context (i.e., global lexical environment) are also available to the functional context. Similarly, if the current function has another function inside it, the inner function has access to the lexical environment of the outer function as well as the global context. This is because the current context's lexical environment has a reference to its parent's lexical environment. This is called Scope Chain.
If a variable is not found in the current context, it will look up in the scope chain till it reaches the global context. If the variable is not found until the global context, it will throw a reference error. Also, the variables and arguments are available to consume inside the inner functions (like callback functions). Even after the outer function has completed executing, the outer lexical environment will still be present as long as the variables are referred in the inner/callback functions. This behaviour is called Closure.
If we inspect this code, var1 is in the global context, var2 and arg1 are in test functional context. They are still available to access in innerTest. So, the above code will produce the following output. But the reverse is not true. The inner function context can't be accessed from parent function context.
inside innerTest 10 20 5
Execution Stack
As the call stack stores and executes the execution contexts, it is also known as the execution stack. All execution contexts go through creation, execution and deletion phases.
When the GEC becomes the active execution context (i.e., no FEC is present in the call stack), the call stack is considered as empty. GEC stays in the call stack through out the JS program execution. It is popped out only when all the code and callback tasks are executed or when the JS engine is terminated.
So, the execution context is responsible for the seamless execution of JavaScript code. By leveraging lexical environments and scope chaining, we enable powerful features like closures and hoisting. Additionally, the task queue and event loop make JavaScript exceptionally efficient at handling complex tasks with ease and minimal resource consumption. Explore more examples to deepen your understanding of closures, especially in callback functions. Happy scripting !!