How JavaScript  Works Internally?

How JavaScript Works Internally?

Javascript Working

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 behavior 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 flow of execution 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 created 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. Inside the function, the code is executed 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 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 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 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 own 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 behavior. 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 behavior 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!