How Javascript works

  1. Local Scope
    In JavaScript, a local scope refers to the area within a program where a variable is declared and can be accessed. JavaScript has function-level scope, which means that variables declared inside a function are only accessible within that function.

     function exampleFunction() {
       // This variable 'localVariable' is within the local scope of the function.
       var localVariable = "I am a local variable";
       console.log(localVariable);
     }
     exampleFunction(); // Output: I am a local variable
     // This will result in an error because 'localVariable' is not accessible outside the function.
     console.log(localVariable); // Error: localVariable is not defined
    

    The let and const keywords allow for block-level scoping, which means variables declared with let and const are confined to the block (a set of statements surrounded by curly braces {}) in which they are defined, rather than just the function. This is in contrast to the var keyword, which is function-scoped.

     function exampleFunction() {
       if (true) {
         let blockVariable = "I am a block-scoped variable";
         console.log(blockVariable);
       }
       // This will result in an error because 'blockVariable' is not accessible here.
       console.log(blockVariable); // Error: blockVariable is not defined
     }
     exampleFunction(); // Output: I am a block-scoped variable
    

    In this example, blockVariable is only accessible within the block where it is declared.

  2. Global Scope
    In JavaScript, the global scope refers to the outermost scope in a program, where variables and functions are accessible from any part of the code. When you declare a variable or a function outside of any block or function, it becomes part of the global scope.

     // Global variable
     var globalVar = "I am a global variable";
    
     function myFunction() {
       // Accessing the global variable inside a function
       console.log(globalVar);
     }
     myFunction(); // Outputs: I am a global variable
    
     // Global function
     function globalFunction() {
       console.log("I am a global function");
     }
     globalFunction(); // Outputs: I am a global function
    

    In this example, globalVar and globalFunction are in the global scope. They can be accessed and used anywhere in the code, both inside and outside functions.
    However, it's generally considered good practice to minimize the use of global variables to avoid unintended side effects and potential naming conflicts.

  3. Execution Context

    In JavaScript, an execution context is an abstract concept that encompasses the environment in which JavaScript code is executed. Understanding execution contexts is crucial for comprehending how JavaScript code runs. There are two main types of execution contexts in JavaScript,

    i) Global Execution Context

    The global execution context is the default or outermost context.

    It is created when the JavaScript code is executed, and it represents the global scope.

    In a browser environment, the global object is the window object.
    ii) Function Execution Context

    Each time a function is invoked, a new function execution context is created.

    It includes the function's local variables, parameters, and a reference to the outer (enclosing) execution context.

    The context is popped off the stack when the function execution completes.

    Each execution context has two phases -
    Creation phase and Execution phase.

  4. Scope Chain
    In JavaScript, the scope chain refers to the hierarchical structure of scopes that a program maintains during its execution. A scope in JavaScript is a region of code where a variable can be accessed or modified. Scopes can be nested within each other, creating a scope chain.

    When a variable is referenced in JavaScript, the interpreter searches for that variable in the current scope. If the variable is not found, it looks in the outer scope, continuing this process until the variable is found or the global scope is reached.

     var globalVariable = 'I am global';
    
     function outerFunction() {
       var outerVariable = 'I am outer';
    
       function innerFunction() {
         var innerVariable = 'I am inner';
         console.log(globalVariable);  // Access global variable
         console.log(outerVariable);  // Access variable from the outer function
         console.log(innerVariable);  // Access variable from the current function
       }
       innerFunction();
     }
     outerFunction();
    
  5. Variable Shadowing
    Variable shadowing in JavaScript occurs when a variable declared within a certain scope has the same name as a variable in an outer scope. This can lead to unexpected behavior, as the inner variable "shadows" or takes precedence over the outer variable within its scope.

     let x = 10; // Outer variable
    
     function example() {
       let x = 5; // Inner variable, shadows the outer variable within this function's scope
       console.log(x); // Prints 5, referring to the inner variable
     }
     example();
     console.log(x); // Prints 10, referring to the outer variable
    
  6. Hoisting
    Hoisting in JavaScript is a behavior where variable and function declarations are moved to the top of their containing scope during the compilation phase, before the code is executed. This allows you to use variables and functions before they are declared in your code.
    It's important to note that only the declarations are hoisted, not the initialization or assignments.

    i) Variable Hoisting
    In the example, the declaration var x; is hoisted to the top, but the assignment (x = 5;) is not hoisted. So, when you try to log x before the assignment, it prints undefined.

     console.log(x);  // Output: undefined
     var x = 5; // if you use const then it will give referenceError
     console.log(x);  // Output: 5
    

    ii) Function Hoisting
    In this example, the entire function declaration is hoisted to the top. Therefore, you can call the function before its actual declaration in the code.

     sayHello();  // Output: "Hello, World!"
     function sayHello() {
         console.log("Hello, World!");
     }
    

    However, there are some differences between function declarations and function expressions in terms of hoisting,

     // Function Declaration
     hoistedFunction();  // Output: "I'm hoisted!"
     function hoistedFunction() {
         console.log("I'm hoisted!");
     }
    
     // Function Expression
     nonHoistedFunction();  // Error: nonHoistedFunction is not a function
     var nonHoistedFunction = function() {
         console.log("I'm not hoisted!");
     };
    

    In the case of function expressions (where a function is assigned to a variable), only the variable declaration is hoisted, not the function assignment. Therefore, trying to call the function before the assignment results in an error.
    It's important to be aware of hoisting in JavaScript to avoid unexpected behavior in your code. To improve code readability and avoid issues, it's often recommended to declare variables at the top of their scope and define functions before they are called.

  7. How Javascript Engine Works
    JavaScript code gets executed in a multi-step process, involving various phases and components. Here is an overview of the typical process,
    i) Tokenization/Lexical Analysis
    The JavaScript engine breaks the source code into meaningful chunks called tokens. This process is known as tokenization or lexical analysis.

    ii) Parsing/Abstract Syntax Tree (AST) Generation
    The engine then parses the tokens and generates an Abstract Syntax Tree (AST). The AST represents the syntactic structure of the code, showing how different elements are related.

    iii) Execution Context Creation
    The engine creates an initial execution context, known as the global execution context, for the entire script. This context includes the global object (e.g., window in a browser), the this reference (pointing to the global object in non-strict mode), the outer environment (null for the global context), and a reference to the global variable object.

    iv) Hoisting
    During the creation phase of the execution context, variable and function declarations are hoisted. Variables are initialised to undefined, and function declarations are fully hoisted. This allows you to use functions and variables before their actual declarations in the code.

    v) Execution and Context Stack (Call Stack)
    The engine starts executing the code line by line. As it encounters function calls, new execution contexts are created and pushed onto the call stack. Each function's context includes its own set of local variables, parameters, and a reference to its outer environment.

    vi) Scope Chain
    JavaScript uses a scope chain to resolve variable references. Each function's scope includes not only its own variables but also variables from its outer (enclosing) scopes. The scope chain is used to find and access variables during execution.

    vii) Execution and Variable Assignment
    The engine executes the code, assigning values to variables and performing operations. Function calls create new execution contexts, and the call stack reflects the hierarchy of currently executing functions.

    viii) Asynchronous Callbacks and Event Loop
    Asynchronous operations, such as timers, AJAX requests, or user interactions, are handled using callback functions. These callbacks are placed in the callback queue when the associated events occur. The event loop constantly checks the call stack and the callback queue, moving callbacks to the call stack when it is empty.

    ix) Memory Management and Garbage Collection

    The engine manages memory allocation and de-allocation, including garbage collection to free up memory that is no longer in use.

  8. Global Execution Context
    In JavaScript, the global execution context is the outermost or top-level context in the execution stack. When a JavaScript program is run, the global execution context is created first.
    It consists of two main components,
    i) Global Object
    In a browser environment, the global object is window. In Node.js, it is global. The global object is a container for various properties and methods that are accessible globally. For example, functions like setTimeout and console.log are properties of the global object.
    ii) Global Scope
    The global scope encompasses variables and functions that are defined outside of any function or block. Variables declared in the global scope are accessible throughout the entire program.
    iii) Additionally, the global execution context sets up the following:

    this: In the global context, this refers to the global object (window in browsers, global in Node.js).

    When a JavaScript program starts running, the global execution context is created, and code is executed line by line. Functions and variables declared in the global scope are available throughout the entire program. Other execution contexts are created when functions are called, and they have their own scope chains and local variables.

  9. Call Stack
    The call stack is a critical concept in JavaScript's runtime environment, providing a mechanism for managing the flow of execution in a program. It keeps track of the currently executing functions and their contexts during the execution of a script.
    In JavaScript, when a function is called, a new execution context for that function is created, including information such as local variables and the current position in the code. These execution contexts are organized in a stack-like structure known as the call stack.
    Here's a simplified explanation of how the call stack works:
    i) Function Call: When a function is called, a new execution context is created for that function, and it is pushed onto the call stack.
    ii) Execution: The code inside the function is executed line by line within its execution context.
    iii) Return: When the function completes its execution or encounters a return statement, the execution context is popped off the call stack.
    iv) Control Flow: The control is then transferred back to the previous execution context on top of the stack, and the program continues its execution from where it left off.
    This process repeats as functions are called and return, forming a stack of execution contexts.

  10. Callback Queue
    In JavaScript, the callback queue is closely associated with the event loop and is a key concept in handling asynchronous operations. The callback queue holds functions (callbacks) that are ready to be executed, but they are waiting for the execution stack to be empty.
    Here's a brief overview of how the callback queue works in conjunction with the event loop,
    i) Execution Stack
    The execution stack is where the JavaScript engine keeps track of the functions that are currently being executed. When a function is called, its execution context is pushed onto the stack, and when the function completes, its context is popped off the stack.
    ii) Callback Queue
    The callback queue holds functions (callbacks) that are scheduled to be executed as a result of asynchronous events. These events could be I/O operations, timer events (such as setTimeout or setInterval), or other asynchronous operations.
    iii) Event Loop
    The event loop continuously checks the state of the call stack and the callback queue. If the call stack is empty, and there are functions in the callback queue, the event loop will move a function from the callback queue to the call stack for execution.

  11. Temporal Dead Zone
    In JavaScript, the term "temporal dead zone" (TDZ) refers to a specific behavior related to the hoisting of variables declared with the let and const keywords. The temporal dead zone is the period between the start of the execution of a scope (such as a function or a block) and the point where a variable is declared. During this period, if you try to access the variable, a ReferenceError will be thrown.
    Here's an example to illustrate the temporal dead zone:

    console.log(variable); // ReferenceError: variable is not defined
    let variable = 42;
    console.log(variable); // 42
    

    In this example, even though the console.log(variable) statement appears before the variable declaration, it throws a ReferenceError because the variable is still in the temporal dead zone at that point. Only after the let variable = 42; declaration statement is encountered during the execution, the variable becomes accessible.
    It's important to note that the temporal dead zone only applies to variables declared with let and const, not to variables declared with var.

  12. https://cabulous.medium.com/how-v8-javascript-engine-works-5393832d80a7