1. How JavaScript works internally (engine + runtime) ?

To understand how JavaScript works internally, we must separate two things:

  1. JavaScript Engine

  2. JavaScript Runtime Environment

1. JavaScript Engine

Definition

A JavaScript engine is responsible for executing JavaScript code.

Example engines:

  • V8 (Chrome, Node.js)

  • SpiderMonkey (Firefox)

  • JavaScriptCore (Safari)

How the Engine Works

Step 1: Parsing

  • JS code is parsed

  • Converted into AST (Abstract Syntax Tree)

Example:

Converted into structured tree format.

Step 2: Compilation

Modern engines use JIT (Just-In-Time) compilation.

  • Code is compiled into machine code

  • Optimized during execution

V8 has:

  • Ignition (Interpreter)

  • TurboFan (Optimizer)

Step 3: Execution

  • Code runs in the Call Stack

  • Variables stored in Memory Heap

Engine Components

  • Call Stack → Executes functions

  • Memory Heap → Stores objects and variables

2. JavaScript Runtime

The engine alone cannot handle:

  • Timers

  • HTTP requests

  • DOM manipulation

The runtime environment provides these.

Browser Runtime Includes

  • Web APIs (setTimeout, fetch, DOM)

  • Event Loop

  • Callback Queue

  • Microtask Queue

Node.js Runtime Includes

  • libuv

  • Event Loop

  • File system APIs

  • OS-level APIs

How Everything Works Together

Example:

Flow:

  1. console.log runs in Call Stack

  2. setTimeout goes to Web API

  3. After delay → callback goes to Task Queue

  4. Event Loop moves it to Call Stack

  5. Executes callback

Output:
Start
End
Timeout

Execution Model Summary

  1. JS Engine parses and compiles code

  2. Call Stack executes synchronous code

  3. Async tasks handled by runtime (Web APIs / libuv)

  4. Event Loop manages execution order

  5. Microtasks run before macrotasks

2. JavaScript memory model

The JavaScript memory model explains how memory is allocated, stored, and managed during code execution.

JavaScript automatically manages memory using garbage collection.

1. Memory Components

JavaScript mainly uses two memory areas:

  1. Stack

  2. Heap

1. Stack Memory

  • Stores primitive values

  • Stores function execution contexts

  • Works in LIFO (Last In, First Out) order

  • Faster access

Stored in stack:

  • number

  • string

  • boolean

  • null

  • undefined

  • symbol

  • bigint

Example:

Here:

  • a and b are stored separately in stack

  • Copy is independent

2. Heap Memory

  • Stores objects and reference types

  • Dynamic memory allocation

  • Slower than stack

Stored in heap:

  • Objects

  • Arrays

  • Functions

Example:

Here:

  • Object stored in heap

  • obj1 and obj2 store reference in stack

  • Both point to same heap memory

3. Execution Context

When a function runs:

  • New execution context is created

  • Stored in Call Stack

  • Variables stored in memory

Example:

  • greet execution context pushed to stack

  • After execution → popped

4. Garbage Collection

JavaScript automatically frees memory using Garbage Collection.

How It Works

Mark-and-Sweep algorithm:

  1. Mark reachable objects

  2. Remove unreachable objects

If no references exist → memory is cleaned.

Example:

Old object becomes unreachable → garbage collected.

Memory Leak

Occurs when:

  • Objects remain referenced unnecessarily

  • Garbage collector cannot free memory

Common causes:

  • Unremoved event listeners

  • Global variables

  • Closures holding references

3. Heap vs stack memory

JavaScript uses two main memory areas:

  1. Stack Memory

  2. Heap Memory

1. Stack Memory

Definition

Stack memory is used to store:

  • Primitive values

  • Function execution contexts

  • Local variables

It follows LIFO (Last In, First Out).

Characteristics

  • Stores values directly

  • Fixed size

  • Very fast access

  • Automatically managed

  • Used for function calls

Example (Primitive Copy)

Here:

  • a and b are stored separately in stack

  • Copy is independent

2. Heap Memory

Definition

Heap memory is used to store:

  • Objects

  • Arrays

  • Functions

It stores data dynamically.

Characteristics

  • Stores reference types

  • Large memory area

  • Slower than stack

  • Managed by garbage collector

Example (Reference Copy)

Here:

  • Object stored in heap

  • obj1 and obj2 hold reference in stack

  • Both point to same heap object

4. Garbage collection in JavaScript

Garbage Collection (GC) is the automatic process of freeing memory that is no longer used by the program.

JavaScript has automatic memory management, so developers do not manually allocate or free memory.

Why Garbage Collection Is Needed

When objects are created:

Memory is allocated in the heap.

If memory is never released:

  • Application slows down

  • Memory leaks occur

  • Browser crashes

Garbage collection prevents this.

How Garbage Collection Works

Modern JavaScript engines use the Mark-and-Sweep algorithm.

Mark-and-Sweep Algorithm

Step 1: Mark

  • Start from root references (global variables, current execution context)

  • Mark all reachable objects

Step 2: Sweep

  • Remove all unmarked (unreachable) objects

  • Free their memory

5. Mark-and-sweep algorithm

Mark-and-Sweep is the primary garbage collection algorithm used by modern JavaScript engines to free unused memory.

It removes objects that are no longer reachable from the root.

Why It Is Needed

When objects are created in heap memory, they remain there until garbage collected.

The challenge:
How does the engine know which objects are safe to remove?

Solution:
Mark-and-Sweep.

How It Works (Step-by-Step)

Step 1: Identify Roots

Roots include:

  • Global variables

  • Variables in current call stack

  • Active function scopes

These are always considered reachable.

Step 2: Mark Phase

  • Starting from roots

  • Recursively mark all reachable objects

  • Anything referenced is marked as “in use”

Step 3: Sweep Phase

  • Traverse entire heap

  • Remove objects not marked

  • Free their memory

6. Common memory leaks

A memory leak occurs when memory that is no longer needed is not released because references to it still exist.

This prevents the garbage collector from freeing memory.

1. Global Variables

Objects attached to global scope are never garbage collected until the page closes.

If data keeps growing → memory leak.

2. Unremoved Event Listeners

If DOM elements are removed but their event listeners remain, memory is retained.

If button is removed without removing listener → memory leak.

Fix:

3. Timers (setInterval / setTimeout)

Timers that are never cleared keep references alive.

If not cleared → keeps running forever.

Fix:

4. Closures Holding References

Closures can accidentally retain large objects.

Even if largeData is unused later, closure may retain it.

5. Detached DOM Elements

When elements are removed from DOM but referenced in JS:

If div variable still exists → not garbage collected.

6. Caches That Grow Forever

Objects used as caches without limits:

If never cleared → memory keeps increasing.

7. Circular References (Less Common Now)

Modern GC handles this, but old systems failed here.

How to Prevent Memory Leaks

  • Avoid unnecessary globals

  • Remove event listeners

  • Clear timers

  • Nullify unused references

  • Limit cache size

  • Use WeakMap / WeakSet when appropriate

7. Hidden classes in V8

Hidden Classes are an internal optimization mechanism used by the V8 engine (Chrome, Node.js) to improve property access performance in JavaScript objects.

JavaScript is dynamically typed, but V8 internally tries to make objects behave like statically structured objects using hidden classes.

Why Hidden Classes Are Needed

JavaScript objects are dynamic:

Properties can be added at runtime.

This makes optimization difficult.

To improve performance, V8:

  • Assigns a hidden class to each object

  • Tracks property structure

  • Optimizes access using inline caching

How Hidden Classes Work

When you create objects with the same property structure:

Both objects:

  • Have same properties

  • Added in same order

  • Share the same hidden class

This allows fast property access.

8. Inline caching

Inline Caching (IC) is a performance optimization technique used by JavaScript engines (like V8) to speed up repeated property access and method calls.

It works closely with hidden classes.

Why Inline Caching Is Needed

JavaScript is dynamically typed:

At runtime, the engine must determine:

  • Does user have property name?

  • Where is it located in memory?

Doing this repeatedly is expensive.

Inline caching stores previous lookup information to make future access faster.

How It Works

First time property is accessed:

Engine:

  • Looks up property

  • Finds its location

  • Stores the result in cache

Next time:

  • Skips full lookup

  • Uses cached information

  • Much faster

Types of Inline Caching

1. Monomorphic

Property accessed on objects with same hidden class.

If all user objects have same structure → optimized.

Best performance.

2. Polymorphic

Property accessed on few different object shapes.

Still optimized but slightly slower.

3. Megamorphic

Property accessed on many different object shapes.

Optimization fails → slower performance.

9. V8 optimization techniques

V8 (Chrome & Node.js engine) uses multiple internal optimizations to make JavaScript execution fast despite being dynamically typed.

1. Just-In-Time (JIT) Compilation

How It Works

V8 does not just interpret code.

It uses:

  • Ignition → Interpreter

  • TurboFan → Optimizing compiler

Flow:

  1. Code is interpreted

  2. Frequently executed code (“hot code”) is detected

  3. TurboFan compiles it into highly optimized machine code

2. Hidden Classes

V8 assigns hidden classes to objects with similar structure.

If objects share the same property order → same hidden class → faster access.

3. Inline Caching (IC)

Caches property lookup results to avoid repeated dynamic resolution.

Best case: Monomorphic (same object shape).
Worst case: Megamorphic (many shapes).

4. Fast Properties

If object structure remains stable:

  • V8 stores properties in optimized format

  • Access becomes very fast

If properties are added/deleted dynamically:

  • Object becomes “dictionary mode”

  • Slower access

10. Referential transparency

A function is referentially transparent if it always produces the same output for the same input and has no side effects.

This means the function call can be replaced with its returned value without changing the program’s behavior.

Key Conditions

A function is referentially transparent if:

  1. Same input → Same output

  2. No side effects

    • Does not modify external variables

    • Does not change global state

    • Does not perform I/O

    • Does not mutate arguments

Side Effects That Break Transparency

  • Modifying global variables

  • Mutating objects

  • Logging

  • API calls

  • DOM manipulation

  • Random values

  • Date/time usage

11. Side effects in JavaScript

A side effect occurs when a function modifies something outside its own scope or interacts with external state beyond returning a value.

Examples of Side Effects

1. Modifying Global Variables

This modifies external state → Side effect.

2. Modifying Function Arguments

Mutates object → Side effect.

3. DOM Manipulation

Changes UI → Side effect.

4. API Calls

Interacts with external system → Side effect.

5. Logging

Writes to console → Side effect.

6. Timers

Asynchronous behavior → Side effect.

7. Using Random or Date

Different output each time → Not pure → Side effect-like behavior.

12. Function composition

Function composition is a functional programming technique where multiple functions are combined to produce a new function.

The output of one function becomes the input of the next.

Basic Example

Flow:

10 → add5 → 15 → multiply2 → 30

Why Function Composition Is Important

  • Encourages reusable small functions

  • Improves readability

  • Makes code modular

  • Core concept in functional programming

  • Used heavily in libraries like Redux and RxJS

13. compose vs pipe

Both compose and pipe are used for function composition.
The only difference is the direction in which functions are executed.

1. compose

Definition

compose executes functions from right to left.

compose(f, g, h)(x) → f(g(h(x)))

Implementation

Example

Execution:

10 → add5 → 15 → multiply2 → 30

Right to left execution.

2. pipe

Definition

pipe executes functions from left to right.

pipe(f, g, h)(x) → h(g(f(x)))

Implementation

Example

Execution:

10 → add5 → 15 → multiply2 → 30

Left to right execution.

14. Currying

Currying is a functional programming technique where a function with multiple arguments is transformed into a sequence of functions, each taking one argument at a time.

Instead of:

It becomes:

Basic Example

Normal function:

Curried version:

15. Pure functions

Definition

A pure function is a function that:

  1. Always returns the same output for the same input

  2. Has no side effects

It does not modify external state or depend on it.

Example of Pure Function

No external dependency → Pure.

16. Benefits of pure functions

1. Predictability

Same input → Same output.

Easy to reason about behavior.

No hidden dependencies.

2. Easier Testing

No need to mock:

  • Global variables

  • API calls

  • DOM

  • External state

Example:

Simple unit testing.

3. No Side Effects

Pure functions:

  • Do not mutate data

  • Do not change global state

  • Do not create unexpected bugs

This reduces debugging complexity.

4. Better Maintainability

  • Clear input → output relationship

  • No hidden behavior

  • Easier to refactor

Code becomes cleaner and modular.

17. Memoization

Memoization is an optimization technique where the results of expensive function calls are cached, so if the same inputs occur again, the cached result is returned instead of recomputing.

It improves performance by avoiding repeated calculations.

Example Without Memoization

The function runs every time.

Example With Memoization

Now it calculates only once.

Why Memoization Works Well

  • Works best with pure functions

  • Output depends only on input

  • No side effects

18. RxJS

RxJS (Reactive Extensions for JavaScript) is a library for reactive programming using Observables to handle asynchronous data streams.

It allows you to work with events, HTTP requests, timers, and user interactions as streams of data.

Why RxJS Is Needed

JavaScript async handling:

  • Callbacks → Callback hell

  • Promises → Single value, limited cancellation

RxJS solves this by:

  • Handling multiple values over time

  • Supporting cancellation

  • Providing powerful operators

Core Concept: Observable

An Observable represents a stream of values over time.

Example:

Output:

Hello
World

19. Observables

An Observable is a stream of data that emits values over time.

It is a core concept in RxJS and reactive programming.

An Observable can emit:

  • Multiple values

  • Over time

  • Asynchronously

Why Observables Are Needed

JavaScript async tools:

  • Callback → Hard to manage

  • Promise → Only one value

  • Observable → Multiple values + cancellation + operators

Basic Example

Output:

1
2
3

20. Promises vs Observables

Both are used to handle asynchronous operations, but they differ significantly in behavior and capabilities.

1. Promise

Definition

A Promise represents a single asynchronous value that will be available in the future.

It resolves once (or rejects once).

Example

Emits one value

 Cannot be cancelled
 Eager execution (starts immediately)

2. Observable (RxJS)

Definition

An Observable represents a stream of multiple values over time.

It can emit zero, one, or many values.

Example

Can emit multiple values

 Can be cancelled (unsubscribe)
 Lazy execution (runs on subscribe)

21. Backpressure

Backpressure is a situation where a data producer generates data faster than the consumer can process it.

It is a flow-control mechanism to prevent memory overload and performance issues.

Simple Explanation

Producer → Sends data
Consumer → Processes data

If producer is faster than consumer → Data builds up → Memory increases → System slows down.

Backpressure helps control this imbalance.

How Backpressure Is Handled

Common strategies:

  1. Buffering → Store data temporarily

  2. Dropping → Ignore extra data

  3. Throttling → Limit rate

  4. Pausing producer → Resume when ready

22. Web Workers

Web Workers allow JavaScript code to run in a separate background thread, parallel to the main thread.

They are used to perform heavy computations without blocking the UI.

Why Web Workers Are Needed

JavaScript is single-threaded.

Heavy tasks like:

  • Large calculations

  • Image processing

  • Data parsing

  • File compression

Can block the main thread → UI freezes.

Web Workers solve this by moving heavy work to a background thread.

How Web Workers Work

  • Main thread creates a worker

  • Worker runs in separate thread

  • Communication happens using message passing

No shared memory (by default).

23. SharedArrayBuffer & Atomics

These are advanced features used for low-level concurrency and shared memory between threads (like Web Workers).

They enable true parallel computation in JavaScript.

1. SharedArrayBuffer

Definition

SharedArrayBuffer is a special type of memory buffer that can be shared between multiple threads.

Unlike normal ArrayBuffer, it allows multiple workers to access the same memory.

Why It Is Needed

Normally, when using Web Workers:

Data is copied (structured clone).

With SharedArrayBuffer:

  • Memory is shared

  • No copying

  • Faster communication

Atomics

Definition

Atomics is a built-in object that provides safe synchronization methods for shared memory.

It prevents race conditions when multiple threads modify shared data.

Why Atomics Is Needed

If two workers modify same memory:

Race condition can occur.

Atomics ensures operations are atomic (completed fully without interruption).

Example

This safely increments index 0.

Common Atomics Methods

  • Atomics.add()

  • Atomics.sub()

  • Atomics.load()

  • Atomics.store()

  • Atomics.compareExchange()

  • Atomics.wait()

  • Atomics.notify()

24. structuredClone

structuredClone() is a built-in function used to create a deep copy of a value.

It performs cloning using the structured clone algorithm, which supports many complex data types.

Introduced in modern browsers and Node.js (v17+).

Why It Is Needed

Older deep copy method:

Problems:

  • Fails with functions

  • Fails with Date

  • Fails with Map/Set

  • Fails with undefined

  • Fails with circular references

structuredClone() solves these issues.

25. structuredClone vs deep copy

A deep copy means creating a completely independent copy of an object, including all nested objects. There are multiple ways to create deep copies manually.

structuredClone() is a built-in modern API that performs deep cloning using the structured clone algorithm.

26. Object.freeze

Object.freeze() is a method used to make an object immutable.

Once an object is frozen:

  • New properties cannot be added

  • Existing properties cannot be removed

  • Existing properties cannot be modified

Syntax

Basic Example

27. Object.seal

Object.seal() is a method that seals an object, preventing new properties from being added and existing properties from being deleted.

However, existing properties can still be modified (if writable).

Syntax

Basic Example

Result:

  • Modification allowed

  • Addition blocked

  • Deletion blocked

28. const vs Object.freeze

1. const

Definition

const prevents reassignment of a variable reference.

It does NOT make the object immutable.

Example

Explanation:

  • Cannot reassign user

  • Can modify properties inside object

2. Object.freeze()

Definition

Object.freeze() makes the object immutable (shallow).

  • Cannot add properties

  • Cannot delete properties

  • Cannot modify properties

Example

Now properties cannot change.

29. Proxy object

A Proxy is an object that wraps another object (target) and intercepts operations performed on it.

It allows you to customize behavior for:

  • Property access

  • Property assignment

  • Function calls

  • Object construction

  • Deletion

  • And more

Why Proxy Is Needed

Normally:

You cannot intercept or control these operations easily.

Proxy allows you to control and redefine these operations.

Basic Syntax

  • target → Original object

  • handler → Object containing traps (interceptors)

Example: Intercepting Property Access

Output:

Accessing name
Lingesh

30. WeakMap

A WeakMap is a collection of key-value pairs where:

  • Keys must be objects

  • Keys are weakly referenced

  • Keys can be garbage collected

It is similar to Map, but with memory management benefits.

Why WeakMap Is Needed

In a normal Map:

Even after obj = null:

  • The object still exists in memory

  • Because Map holds a strong reference

This can cause memory leaks.

WeakMap solves this.

How WeakMap Works

In WeakMap:

Now:

  • Object becomes unreachable

  • Garbage collector removes it

  • Entry automatically disappears

Key Characteristics

  • Keys must be objects

  • Values can be anything

  • No iteration methods

  • No size property

  • Not enumerable

31. WeakSet

A WeakSet is a collection of unique objects where:

  • Only objects can be stored

  • Objects are weakly referenced

  • Objects can be garbage collected

It is similar to Set, but it holds weak references.

Why WeakSet Is Needed

In a normal Set:

Even after obj = null:

  • Object remains in memory

  • Because Set holds strong reference

This may cause memory leaks.

WeakSet solves this.

How WeakSet Works

Now:

  • Object becomes unreachable

  • Garbage collector removes it

  • WeakSet entry disappears automatically

Key Characteristics

  • Stores only objects

  • Weak references (GC-friendly)

  • No size property

  • Not iterable

  • No forEach, keys, values

32. Code splitting & lazy loading

Code Splitting

Definition

Code splitting is a technique where a large JavaScript bundle is split into smaller chunks that can be loaded on demand.

Instead of loading the entire app at once, only necessary code is loaded initially.

Why It Is Needed

Without code splitting:

  • Entire JS bundle loads at once

  • Large initial load time

  • Slower performance

With code splitting:

  • Smaller initial bundle

  • Faster first paint

  • Better performance

Example (Dynamic Import)

Here:

  • math.js is loaded only when button is clicked

  • Not included in initial bundle

2. Lazy Loading

Definition

Lazy loading means loading resources only when they are needed.

It can apply to:

  • JavaScript modules

  • Images

  • Routes

  • Components

Example (Image Lazy Loading)

Image loads only when near viewport.

Example (React Lazy Loading)

Component loads only when rendered.

33. Browser rendering pipeline (CRP)

The Critical Rendering Path (CRP) is the sequence of steps the browser follows to convert HTML, CSS, and JavaScript into pixels on the screen.

It determines how quickly a page becomes visible to the user.

Steps in Browser Rendering Pipeline

1. HTML Parsing → DOM Tree

  • Browser receives HTML

  • Parses it

  • Converts it into DOM (Document Object Model)

Example:

Becomes:

DOM → div → "Hello"

2. CSS Parsing → CSSOM Tree

  • Browser parses CSS

  • Builds CSSOM (CSS Object Model)

Example:

Creates CSS rules tree.

3. JavaScript Execution

  • JS can modify DOM and CSSOM

  • JS can block rendering if not optimized

  • Synchronous scripts delay rendering

4. Render Tree Construction

Browser combines:

DOM + CSSOM → Render Tree

Render tree contains:

  • Visible elements only

  • Computed styles

Elements like display: none are excluded.

5. Layout (Reflow)

  • Browser calculates size and position of each element

  • Determines geometry

This step is called Layout or Reflow.

6. Paint

  • Browser paints pixels on screen

  • Applies colors, shadows, borders, text

7. Composite

  • Layers are combined

  • Final image rendered on screen

Visual Flow

HTML → DOM
CSS → CSSOM
DOM + CSSOM → Render Tree
Render Tree → Layout
Layout → Paint
Paint → Composite

34. Reflow vs repaint

Reflow

Definition

Reflow occurs when the browser recalculates the layout of elements.

It determines:

  • Size

  • Position

  • Geometry of elements

It happens when something affects page structure.

When Reflow Happens

  • Adding/removing DOM elements

  • Changing element size (width, height)

  • Changing font size

  • Changing position

  • Resizing window

  • Reading layout properties (offsetWidth, etc.)

Example

This changes layout → Reflow triggered.

2. Repaint

Definition

Repaint occurs when an element’s appearance changes but layout remains the same.

Only visual updates are applied.

When Repaint Happens

  • Changing color

  • Changing background

  • Changing visibility

  • Changing outline

Example

No layout change → Only repaint.

Key Difference

  • Reflow → Layout recalculation

  • Repaint → Visual update only

  • Reflow is more expensive

  • Reflow often triggers repaint


35. Common JavaScript design patterns

Design patterns are reusable solutions to common software design problems.

In JavaScript, patterns are influenced by:

  • Functions as first-class citizens

  • Prototypes

  • Closures

  • Modules

1. Module Pattern

Purpose

Encapsulate private data and expose public methods.

Example

Uses closure for private variables.

2. Factory Pattern

Purpose

Create objects without exposing the creation logic.

Example

3. Constructor Pattern

Purpose

Create multiple instances using a constructor function.

Example

4. Singleton Pattern

Purpose

Ensure only one instance exists.

Example

36. Dependency injection

Dependency Injection is a design pattern where a class or function receives its dependencies from the outside instead of creating them internally.

In simple terms:
Do not create dependencies inside a class — inject them from outside.

Why DI Is Needed

Without DI → Tight coupling
With DI → Loose coupling

Loose coupling improves:

  • Testability

  • Maintainability

  • Flexibility

Without Dependency Injection 

Problem:

  • Cannot easily replace Database

  • Hard to unit test

With Dependency Injection 

37. Global execution context

The Global Execution Context is the default execution context created when a JavaScript program starts running.

It is the base execution environment where:

  • Global variables are created

  • Functions are defined

  • The this keyword is initialized

It is created automatically by the JavaScript engine.

What Is Execution Context?

An execution context is the environment in which JavaScript code is evaluated and executed.

There are three types:

  1. Global Execution Context

  2. Function Execution Context

  3. Eval Execution Context

What Happens in Global Execution Context?

When JS file runs:

Engine performs two phases:

1. Creation Phase

During this phase:

  • Global object is created

    • Browser → window

    • Node.js → global

  • this is set to global object

  • Memory is allocated for variables and functions

Behavior:

  • var variables → initialized with undefined

  • let and const → created but not initialized (Temporal Dead Zone)

  • Functions → fully stored in memory

2. Execution Phase

  • Code runs line by line

  • Variables assigned actual values

  • Functions executed when called

38. Function execution context

A Function Execution Context is created every time a function is invoked.

It contains everything needed to run that function:

  • Local variables

  • Function parameters

  • arguments object

  • this binding

It is pushed onto the Call Stack when the function is called.

When Is It Created?

Example:

When greet("Lingesh") runs:

  • A new Function Execution Context is created.

Phases of Function Execution Context

Like the Global Execution Context, it has two phases:

1. Creation Phase

During this phase:

  • Memory is allocated for parameters

  • Local variables are initialized

  • arguments object is created

  • this is determined

  • Inner functions are stored

Behavior:

  • var → initialized as undefined

  • let & const → Temporal Dead Zone

  • Functions → fully stored in memory

2. Execution Phase

  • Code runs line by line

  • Variables get assigned actual values

  • Return statement executes

  • Context is removed after completion

39. Phases of execution context

Every execution context (Global or Function) goes through two main phases:

  1. Creation Phase

  2. Execution Phase

1. Creation Phase (Memory Phase)

This happens before the code actually runs.

The JavaScript engine prepares memory.

What Happens in Creation Phase?

1. Global Object Creation

  • Browser → window

  • Node.js → global

2. this Binding

  • In Global Context → this refers to global object

  • In Function Context → depends on how function is called

3. Variable Hoisting

During creation phase:

  • a is created in memory

  • Initialized as undefined

4. let and const

They are hoisted but:

  • Not initialized

  • Stay in Temporal Dead Zone (TDZ)

5. Function Hoisting

Functions are fully stored in memory during creation phase.

They can be called before declaration.

2. Execution Phase

After memory setup:

  • Code runs line by line

  • Variables get assigned real values

  • Functions execute

  • Return statements processed

40. globalThis

globalThis is a standard way to access the global object across all JavaScript environments.

It provides a unified reference to the global object, regardless of whether the code runs in:

  • Browser

  • Node.js

  • Web Worker

Why It Was Introduced

  • Cross-platform consistency

  • Avoid environment checks

  • Standardized in ES2020

41. Race conditions and prevention

A race condition occurs when multiple asynchronous operations access and modify shared data, and the final result depends on the order in which they complete.

It leads to unpredictable and inconsistent behavior.

Why Race Conditions Happen

JavaScript is single-threaded, but:

  • Async operations (Promises, setTimeout, fetch)

  • Web Workers

  • Shared memory (SharedArrayBuffer)

Can execute in non-deterministic order.

Example of Race Condition

Expected balance: 20

Actual result may be incorrect depending on timing.

Because both functions read the same initial value before update.

How to Prevent Race Conditions

1. Use Proper Async Control (await)
2. Use Locks / Mutex (Manual Control)
3. Use Atomic Operations
4. Use Latest Request Wins Pattern
5. Debouncing / Throttling

​42. Error handling in async code

Handling errors in asynchronous code depends on the async pattern used:

  • Callbacks

  • Promises

  • async/await

1. Error Handling in Callbacks (Old Way)

Callbacks usually follow error-first pattern.

Problem:

  • Callback hell

  • Hard to manage

2. Error Handling with Promises

Use .catch().

Errors handled in .catch().