Hey there, JavaScript enthusiastic! Whether you're a seasoned developer traversing intricate codebases or a curious newcomer dipping your toes into the vast ocean of programming, have you ever encountered unexpected behaviour in your JavaScript code? Unlike some languages with straightforward rules, JavaScript has its unique quirks, leading you to wonder, "How does all this magic happen?"
It's only natural to be fascinated by the inner workings that transform seemingly simple lines of code into the dynamic experiences we encounter online every day.
Consider this blog your trusty treasure map, guiding you through the thrilling yet sometimes mysterious landscape of JavaScript execution! But fret not, we're casting aside the bewildering jargon and delving straight into the essence of what makes JavaScript pulse with life. So, gear up and get ready for an adventure where we unravel JavaScript's secrets together!
You may have a question "What is Javascript Execution context?" you can describe Javascript execution context as a stage where its code is executed.
At its core, the execution context in JavaScript represents the environment in which code is executed. It encompasses two fundamental aspects: the memory context and the execution context.
Memory Context
In the memory context, JavaScript stores all variables, functions, and their respective values during code execution. This is where memory allocation occurs, and values are assigned to variables and functions.
Memory context serves as the storage space for all data utilized by the JavaScript code. Whether it's primitive data types like numbers and strings, or complex objects and functions, everything resides within the memory context.
Execution Context
The execution context handles the actual execution of JavaScript code. It manages the order of code execution, keeps track of the currently executing line of code, and handles the scope chain.
JavaScript operates in a stack-based manner with the help of execution contexts. Whenever a function is invoked, a new execution context is created and pushed onto the call stack. Once the function completes execution, its context is popped off the stack, and the control returns to the previous execution context.
Each execution context has its associated memory context. The global execution context represents the overall script environment, while functions create their execution contexts with localized memory contexts for variables and function declarations.
Flow of the Javascript Execution
Understanding how execution contexts work is crucial for grasping the execution flow in JavaScript. Here's a brief overview of the execution flow with example:
The flow of execution context in JavaScript involves two key concepts: Execution context creation and stack management.
Execution context creation
When a JavaScript program starts, a global execution context (GEC) is created. This context holds all globally declared variables and functions. When a function is called, a new function execution context (FEC) is made on top of the stack. This context holds the function's arguments, local variables, and a reference to the this
object.
stack management
The execution contexts are managed using a stack. Think of it like a stack of plates. The GEC is always at the bottom of the stack. When a new function is called, its FEC is pushed onto the stack, becoming the active context. The code is executed inside the function using the variables and functions defined in its FEC and the GEC. When the function finishes execution, its FEC is popped off the stack. This means its variables and functions are no longer accessible.
Here is a Code Example And Visual Representation of the execution flow:
// Global execution context
let globalContext = 10
console.log(globalContext, "global execution context")
function outer() {
// Function execution context
let firstFunctionContext = 11
function inner() {
// Nested Function execution context
let nestedFunctionContext = 13
console.log(nestedFunctionContext, "nested function context")
}
console.log(firstFunctionContext, "first function context")
inner(); // Calling inner function
}
outer(); // Calling outer function
The JavaScript engine initializes the global execution context to set up the global environment and execute global code. Within the global context, the variable globalContext
is declared and assigned the value 10
.
The console logs the value of globalContext
, displaying "10 global execution context".
The next line of code has outer
function declaration that will first be stored in the GEC Memory context.
After this Javascript will jump to the line next to the end of the outer
function. Upon calling the outer
function, a new function execution context is created.
In the above image, you can see one Function Execution Context in the Global Execution Context.
Inside the outer
function's context, the variable firstFunctionContext
is declared and assigned the value 11
. The console logs the value of firstFunctionContext
, displaying "11 first function context".
Now, Javascript will execute the code block of the outer function in its FEC.
Inside the outer
function, the inner
the function is invoked. This action triggers the creation of a nested function execution context within the outer
function's context. Within the inner
function's context, the variable nestedFunctionContext
is declared and assigned the value 13
. The console logs the value of nestedFunctionContext
, displaying "13 nested function context".
Upon completing the execution of the inner
function's code, its execution context is discarded. If the inner
the function had a return value, it would be passed to the outer function's context. Since the inner
function does not return a value, no further action is taken.
With the execution of the inner
the function concluded, its execution context is removed from the call stack. Control returns to the parent execution context, which is the outer
function's context. If there were additional function calls or code within the outer
function, the process would continue accordingly.
This breakdown illuminates how JavaScript orchestrates execution contexts and manages the flow of execution, providing a deeper understanding of the runtime behavior of nested functions.
Key points to remember
Each execution context has its variables and scope. Variables from outer contexts are accessible within inner contexts, but not vice versa. The this
keyword refers to the object that the function was called on, and its value depends on the execution context. Understanding execution contexts is crucial for understanding variable scoping, function behavior, and this
keywords in JavaScript.
Conclusion
Our journey into JavaScript's execution context has been a transformative one. It wasn't just about understanding the technicalities, but about uncovering hidden truths that illuminate seemingly enigmatic behaviour. Remember the confusion surrounding the "undefined" variable? Now, thanks to execution contexts, we know it's not magic, but a logical consequence of memory allocation and variable scope.
This newfound knowledge empowers us to approach future challenges with confidence. No longer will "undefined" be a source of frustration, but a stepping stone to deeper understanding. We can navigate the intricacies of JavaScript with a map in hand, deciphering the mysteries that once seemed like insurmountable barriers, including the curious behaviour of console.log
printing function declaration. It's just got that declaration reference from the memory context.
But our journey doesn't end here! The world of JavaScript execution context holds even more secrets to uncover. Each new concept unlocks possibilities and allows us to wield this dynamic language with greater precision. So, let's keep exploring, keep asking questions, and keep demystifying the magic of JavaScript, one execution context at a time!