An open API service indexing awesome lists of open source software.

https://github.com/ahadalireach/javascript.interview.questions

A repository containing JavaScript concepts with interview questions, code implementations, and practical examples for learning and interviews.
https://github.com/ahadalireach/javascript.interview.questions

javascript javascript-concepts javascript-interview-questions javascript-interview-questions-and-answers

Last synced: 10 months ago
JSON representation

A repository containing JavaScript concepts with interview questions, code implementations, and practical examples for learning and interviews.

Awesome Lists containing this project

README

          

# JavaScript Interview Questions and Answers

---

## ❓ What is JavaScript?

JavaScript is a **high-level**, **interpreted**, **single-threaded**, and **synchronous** programming language used to create interactive websites.

It runs in the browser and can also be used on the backend (Node.js).

- **High-level:** Easy to read and write, handles low-level stuff for you.
- **Interpreted:** Runs code line by line in the browser.
- **Single-threaded:** Can do one thing at a time.
- **Synchronous:** Executes code in order, one step after another.

### But JavaScript Can Also Be Asynchronous:

JS uses tools like:

- `setTimeout()`
- **Web APIs**
- **Promises**
- `async/await`

...to run code in the background without blocking.

---

## ❓ What is the History of JavaScript?

JavaScript was created by **Brendan Eich** in **1995** while working at Netscape.

- Originally called **Mocha**, then renamed to **LiveScript**, and finally **JavaScript**.
- It was developed in just **10 days**.
- Despite the name, JavaScript is **not related to Java**.
- Standardized by **ECMA International** as **ECMAScript** in 1997.
- Today, JavaScript is one of the **core technologies of the web** alongside HTML and CSS.

---

## ❓ Is JavaScript a Compiled or Interpreted Language?

First of all let's understand what is:

### What is a JavaScript Engine?

A **JavaScript Engine** is a program that executes JavaScript code.

- **V8** — Used in Chrome and Node.js
- **SpiderMonkey** — Used in Firefox
- **Chakra** — Used in older Microsoft Edge versions

### Is JavaScript Compiled or Interpreted?

Traditionally, **JavaScript is an interpreted language**, meaning:

- Code is executed **line by line**.
- Earlier engines interpreted JS **without converting to machine code ahead of time**.

But **modern JavaScript engines** use **JIT (Just-In-Time) Compilation**, which makes JavaScript **partially compiled** and **partially interpreted**.

```js
console.log("Hello World"); // Runs first
console.log("Hello Again"); // Runs after the first line
```

> So, JavaScript behaves like an interpreted language but with **JIT compilation** to boost performance.

### What is an Abstract Syntax Tree (AST)?

An **Abstract Syntax Tree (AST)** is a tree-like representation of the source code structure.

- Nodes represent constructs like variables, functions, operators, etc.

- AST is used internally by JavaScript engines for:

- Syntax checking
- Scope management
- Code transformation and optimization

### 🆚 Compiled vs Interpreted Languages

| **Feature** | **Compiled Languages** | **Interpreted Languages** |
| -------------- | ---------------------------- | ------------------------------- |
| **Examples** | C, C++, Rust | JavaScript, Python, Ruby |
| **Execution** | Pre-compiled to machine code | Line-by-line execution |
| **Speed** | Faster after compilation | Slower at runtime |
| **Start Time** | Slower to start | Fast to start |
| **Output** | Machine code | Direct execution by interpreter |

### How Modern JavaScript Works (JIT)

Modern engines like **V8** use **Just-In-Time (JIT) Compilation**:

- JS is parsed into an **AST (Abstract Syntax Tree)**
- Then it's compiled into **bytecode**
- "Hot code" (frequently used code) is **optimized into machine code** during runtime

👉 This gives JavaScript the **speed of compiled languages**
while keeping the **flexibility of interpreted ones**

### Analogy

- **Interpreted**: Reading a book out loud word by word without preparation
- **Compiled**: Translating the book entirely before reading
- **JIT**: Reading out loud and translating parts as you go for speed and efficiency

---

## ❓ What Makes JavaScript Great?

JavaScript is popular for a reason. It’s powerful, flexible, and beginner-friendly.

### Key Reasons:

- **Simplicity:**
Easy to learn, write, and run directly in the browser. No setup needed.

- **Versatility:**
Works on the **frontend** (browser), **backend** (Node.js), and even in **mobile apps** (React Native).

- **OOP + Functional Programming:**
Supports both:

- **Object-Oriented Programming** (classes, objects, inheritance)
- **Functional Programming** (first-class functions, callbacks)

- **Asynchronous Power:**
Handles slow tasks like API calls using:

- Callbacks
- Promises
- `async/await`

- **Huge Ecosystem:**
Massive community, lots of libraries and frameworks like:
- React
- Angular
- Vue

---

## ❓ What Are JavaScript's Weaknesses?

Even though JavaScript is powerful and popular, it has some limitations.

### Key Weaknesses:

- **Security Issues:**
JavaScript runs on the client side, so it’s exposed to attacks like XSS (Cross-Site Scripting).

- **Browser Dependency:**
Behavior may vary across browsers due to differences in engine implementations.

- **Single-threaded:**
It can only do one thing at a time. Heavy tasks can block the UI and make the page unresponsive.

- **Global Scope Pollution:**
If not carefully managed, too many global variables can cause conflicts.

- **Debugging Async Code:**
Debugging Promises or `async/await` can be tricky, especially for beginners.

---

## ❓ What is JSON?

**JSON** stands for **JavaScript Object Notation**

It’s a:

- Lightweight
- Self-descriptive
- Easy-to-read

A **data format used for exchanging data between server and client**

### JSON Object Example

```json
{
"name": "Ahad Ali",
"age": 22,
"isDeveloper": true,
"skills": ["JavaScript", "React"],
"profile": {
"linkedin": "ahadalireach",
"location": "Pakistan"
}
}
```

### `JSON.parse()` — Convert JSON String → JS Object

Use when you **receive JSON from a server** (as a string) and want to convert it to a **JavaScript object**.

```js
const jsonData = '{"name":"Ahad","age":22}';
const obj = JSON.parse(jsonData);

console.log(obj.name); // ✅ "Ahad"
```

- `JSON.parse()` ka use tab hota hai jab string ko JavaScript object mein convert karna ho.

### `JSON.stringify()` — Convert JS Object → JSON String

Use when you want to send data to a server.
Server string hi accept karta hai, is liye object ko string banana padta hai.

```js
const obj = { name: "Ahad", age: 22 };
const jsonString = JSON.stringify(obj);

console.log(jsonString); // ✅ '{"name":"Ahad","age":22}'
```

- `JSON.stringify()` se hum JS object ko JSON string bana kar send karte hain.

---

## ❓ What is a Thread of Execution?

A **thread of execution** is the path a program follows while running your code — one line at a time.

In simple terms, a thread is a **single, sequential flow** of instructions.

### In JavaScript:

- JavaScript is **single-threaded**, meaning it has only **one main thread** to execute all code.
- Everything runs **line by line** — one task at a time.
- This thread manages two main things:
- **Call Stack:** Tracks function calls and execution order.
- **Memory Heap:** Stores variables and objects.

### In Simple Words:

> It’s **how JavaScript runs your code from top to bottom, one step at a time.**

```js
console.log("1");
console.log("2");
console.log("3");
console.log("4");
```

```
1
2
3
4
```

![Execution of Thread](thread.png)

JavaScript executes one statement, then moves to the next — just like reading a book.

---

## ❓ What is the Call Stack?

The **Call Stack** is a data structure that JavaScript uses to **keep track of function calls**.

It follows the **LIFO (Last In, First Out)** principle.
The last function that enters the stack is the first one to finish and be removed.

> The Call Stack is like a **to-do list** for functions.
> JavaScript keeps track of "what to run next" using this stack.

> The call stack manages **function execution one by one**.
> New function calls are added on top. When a function finishes, it's removed from the top.
> The **Global Execution Context** is always at the bottom.

> Any code must go through the **call stack** before it gets executed.

```js
function first() {
console.log("first...");
second();
}

function second() {
console.log("second...");
third();
}

function third() {
console.log("third...");
}

// Calling out of order
third();
second();
first();
```

### Step-by-Step Breakdown

1. `third()` is called:

```console
third...
```

- `third()` is pushed to the call stack
- It executes and prints "third..."
- Then it is popped off after execution

2. `second()` is called:

```console
second...
third...
```

- `second()` is pushed to the call stack
- It calls `third()` → `third()` is pushed
- `third()` executes and is popped
- Then `second()` finishes and is popped

3. `first()` is called:

```console
first...
second...
third...
```

- `first()` is pushed to the call stack
- It calls `second()` → pushed
- `second()` calls `third()` → pushed
- Then they finish in reverse:
- `third()` → popped
- `second()` → popped
- `first()` → popped

### How It Works

> Every time a function is called, it is **pushed** onto the **Call Stack**.
> When it finishes, it is **popped off**.

| Before Execution | Nested Calls in Stack |
| ----------------------------------------------------- | ----------------------------------------------------- |
| | |

---

## ❓ What is Execution Context?

The **Execution Context** is like a **workspace** or **container** where JavaScript runs your code.

Whenever your code runs, a new execution context is created.
This environment handles the **transformation and execution** of your code and contains all the info JavaScript needs to run it properly.

> Everything in JavaScript runs **inside an execution context**.

### Components of Execution Context:

1. **Memory Component (Creation Phase / Variable Environment):**

- Stores variables and function declarations
- Sets up the scope chain
- Binds the `this` keyword

2. **Code Component (Execution Phase / Thread of Execution):**
- Executes code line-by-line
- Runs function logic and expressions

### Visual Representation:

| Memory Phase | Execution Phase |
| ---------------------------------------------- | ---------------------------------------------- |
| | |

### Types of Execution Context:

- **Global Execution Context (GEC):**

- Created by default when JavaScript starts executing your file
- Only one GEC exists at a time

- **Function Execution Context (FEC):**

- Created **every time a function is called**
- Each has its own memory and code components

- **Eval Execution Context (EEC):**
- Rare and created when code is run using `eval()`

> JavaScript uses the **Call Stack** to manage all execution contexts.First, the **Global Execution Context (GEC)** is pushed.Every time a function is called, a new **Function Execution Context (FEC)** is pushed on top.As each function completes, its context is popped off — one by one.

---

## ❓ What is the Global Execution Context (GEC)?

The **Global Execution Context (GEC)** is the first environment created when JavaScript starts running your code.
It represents the **global scope** and provides a base where all global code runs.

- **Created automatically** when the script begins execution
- Stores all **global variables** and **function declarations**
- Sets up the **global object** and binds `this` to it
- Only **one GEC** exists at any given time

### Two Phases of GEC:

1. **Memory Creation Phase (Hoisting):**

- All variables are allocated memory and initialized with `undefined`
- Function declarations are stored entirely

2. **Execution Phase:**
- Code is executed **line-by-line**
- Variables are assigned actual values

### What is the Global Object?

The **global object** is a special object that holds all global-level variables and functions.

- In **browsers**, it's called `window`
- In **Node.js**, it's called `global`

```js
var a = 10;

console.log(a); // Output: 10
console.log(window.a); // Output: 10 (in browsers)
console.log(global.a); // Output: 10 (in Node.js)
```

> The value of `this` inside the Global Execution Context points to the global object.

---

## ❓ What is Function Execution Context (FEC)?

The **Function Execution Context (FEC)** is created **every time a function is invoked** in JavaScript.
It is a private environment used to run the specific function’s code.

Each FEC contains:

- Arguments object
- Local variable scope
- Reference to outer environment

Each function call creates a new execution context that is:

- **Pushed onto the call stack**
- **Executed**
- **Popped off** once the function completes

> This context is **temporary** and exists only during the lifetime of the function execution.

```js
let a = 10; // Global variable
let b = 20; // Global variable

function add(a, b) {
return a + b; // Executes inside FEC
}

let result = add(a, b); // Creates FEC
console.log(result); // Output: 30
```

> Each function runs in its own **isolated context** and then returns control back to the previous context (usually GEC).

---

## ❓ What is Eval Execution Context (EEC)?

The **Eval Execution Context (EEC)** is created whenever JavaScript runs code using the `eval()` function.

It behaves similarly to other execution contexts, with its own memory and execution phase, but is considered dangerous and discouraged.

- Created when `eval()` is used to **execute a string of code**
- Has its own **execution context and variable environment**
- Can introduce or override global variables
- **Rarely used** due to **security** and **performance** issues

```js
eval("var a = 10;"); // Creates Eval Execution Context
console.log(a); // Output: 10 (in global scope)
```

> ⚠️ Avoid using `eval()` in production. It can lead to vulnerabilities and unpredictable behavior.

---

## ❓ What is Scope? What are its Types?

Scope determines where variables can be **accessed** in your code.
It defines the **visibility** and **lifetime** of variables.

> The region where we can access the variable is known as the scope for that variable.

### JavaScript supports 4 types of scope:

- **Global Scope**
- **Function Scope**
- **Block Scope**
- **Module Scope**

### Global Scope:

- Variables declared **outside** of any function or block are in the global scope
- Accessible throughout the file and other files (if attached to the global object)
- In the browser, the global object is `window`; in Node.js, it's `global`

```js
var a = 10;
console.log(window.a); // 10 in browser
```

```js
function sayHi() {
console.log(this); // refers to window in non-strict mode
}
```

### Module Scope:

- Each JavaScript module (using `import`/`export`) has its own scope
- Variables/functions declared in a module are not global unless explicitly exported

```js
// index.js
export const name = "Ahad";

// app.js
import { name } from "./index.js";
console.log(name);
```

### Function Scope:

- Each time a function is called, a new scope is created
- Variables declared with `var` inside functions are scoped to that function

```js
function sayHi(name) {
var greeting = "Hi " + name;
return greeting;
}

console.log(sayHi("Ahad"));
```

### Block Scope:

- Introduced with ES6 using `let` and `const`
- Variables declared inside `{}` (e.g. in `if`, `for`) are block-scoped

```js
{
let x = 5;
const y = 10;
console.log(x, y);
}
// x and y are not accessible here
```

> Always prefer `let` and `const` for safer, block-scoped variables.

---

## ❓ What is Scope Chain, Lexical Scope, and Lexical Environment?

### Scope Chain

The **Scope Chain** is the process JavaScript uses to **resolve variable names**.

- When a variable is referenced, the JS engine looks in the **current scope**.
- If not found, it goes **upward** to the **parent scopes**, all the way to the **global scope**.
- This forms a "chain" of scopes.

```js
let a = 10;

function outer() {
let b = 20;

function inner() {
let c = 30;
console.log(a); // ✅ 10 (from global scope)
console.log(b); // ✅ 20 (from outer)
console.log(c); // ✅ 30 (own scope)
}

inner();
}

outer();
```

> Scope Chain Order:

- Inner function scope
- Outer function scope
- Global scope

`OR`

**Scope chain** is how JavaScript looks for variables:
👉 If a variable is not found in the current scope, JS looks outward in the parent scope — until it reaches the global scope.

```js
let a = "Global";

function outer() {
let b = "Outer";

function inner() {
let c = "Inner";
console.log(a); // ✅ Looks in global
console.log(b); // ✅ Looks in outer
console.log(c); // ✅ Local
}

inner();
}

outer();
```

> Concept: The inner function has access to variables of its outer functions due to scope chain.

### Lexical Scope

**Lexical Scope** (also called static scope) means:

- A variable's accessibility is determined by its position in the source code, not where it is called.
- Functions defined inside other functions can access variables from their outer scopes.

```js
let globalVar = "Global";

function outerFunction() {
let outerVar = "Outer";

function innerFunction() {
console.log(globalVar); // ✅ Accesses global
console.log(outerVar); // ✅ Accesses outer
}

innerFunction();
}

outerFunction();
```

> Lexical scope is set when you write the function, not when you call it.

`OR`

Lexical scope ka matlab hai:

- "Function kis jagah likha gaya hai, uss jagah ke variables us function ke liye available honge."
- Yeh likhne ke waqt decide hota hai, run-time par nahi.

**Easy Explanation:**
Agar koi function kisi aur function ke andar likha ho, to wo apne parent function ke variables ko access kar sakta hai, even agar wo baad mein kahin aur call ho.

```js
function outer() {
let name = "Ahad"; // 👈 outer scope variable

function inner() {
console.log(name); // ✅ Accesses outer's variable
}

return inner; // 👈 inner function ko return kar dia
}

const greet = outer(); // outer() run hoke inner() return hua
greet(); // inner() run hua
```

**Kya hua yahaan?**

- `inner()` function outer ke andar likha gaya tha.
- To usko outer ka variable name mil gaya.
- Chahe `inner()` function baad mein kahin aur se call ho — scope wahi hoga jahan wo likha gaya tha.

### Lexical Environment

A **Lexical Environment** is an internal structure used by JS to track identifiers (variables/functions) during execution.
`OR`
A **Lexical Environment** is a concept used by JS engine to manage scope.

> Every time a function is called, a new Lexical Environment is created for it.

**Components:**

- Environment Record – Stores variable/function declarations
- Outer Environment Reference – Links to the parent Lexical Environment

```js
function sum(x) {
return function (y) {
return x + y;
};
}

const add5 = sum(5); // x = 5 in this Lexical Environment
console.log(add5(10)); // 15
```

- Here, the inner function remembers `x = 5` even after sum has finished running, because of the lexical environment.

`OR`

Jab **JavaScript** koi function run karti hai, wo ek box banati hai (Environment) jisme:

- Saare variables store hote hain
- Aur reference hota hai outer scope ka (scope chain)

> Is box ko Lexical Environment kehte hain.

```js
function sum(x) {
return function (y) {
return x + y;
};
}

const add5 = sum(5); // yahan ek LE bana jisme x = 5
console.log(add5(10)); // 15 ➡ y = 10, x = 5 already remembered
```

- `sum(5)` jab call hota hai, JS ek Lexical Environment banata hai jisme:
- ` x = 5``
- aur ek inner function store hota hai
- Jab `add5(10)`call hota hai:
- `y = 10`hota hai
- but`x = 5` already saved tha pehle se (due to lexical environment)

> **Lexical Scoping** “Access Rules”
> **Lexical Environment** — “Runtime Storage”

| Concept | Explanation |
| ------------------- | ---------------------------------------------------------------------------- |
| Scope Chain | JS searches for a variable from current → outer → global scope |
| Lexical Scope | Scope is based on **where** a function is **written**, not where it’s called |
| Lexical Environment | Behind-the-scenes structure: record of variables + link to parent scope |

### Real-World Analogy

> **Scope Chain** = "Search path for variables"
> **Lexical Scope** = "Where the function is written decides what it sees"
> **Lexical Environment** = "Notebook that tracks variables + a link to its parent notebook"

---

## ❓ What is Closure?

> A **closure** is a function that retains access to its outer function's variables even after the outer function has completed execution.

In simple terms:

- A function “remembers” the scope in which it was created.
- Even after the outer function is done executing, the inner function still has access to the variables of the outer function.

> A closure is a combination of a function and its **lexical environment** (the variables in scope when the function was created).

### How Closure Works?

```js
// Simple Closure
function makeCounter() {
let count = 0;
return function () {
count++;
return count;
};
}

const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
```

- The inner function “remembers” count from its `outer` lexical environment.
- Even though `makeCounter()` has finished executing, `count` is still accessible.

### Real-World Example: Button Counter

```js
function initCounter(id) {
let count = 0;
return function () {
count++;
document.getElementById(id).innerText = count;
};
}

let counter1 = initCounter("btnCount1");
let counter2 = initCounter("btnCount2");
```

```html
1

2


```

- Each button click updates a **private counter**, and both counters are independent.

### Real-World Example: String Appender

```js
function initAddString(inputId, outputId) {
let str = "";
return function () {
str += " " + document.getElementById(inputId).value;
document.getElementById(inputId).value = "";
document.getElementById(outputId).innerText = str;
};
}

let strAdder1 = initAddString("text1", "text-output1");
let strAdder2 = initAddString("text2", "text-output2");
```

```html

Add String

Add String


```

- Each button maintains its own string state separately using closures.

### Advantages of Closures:

1. **Data Privacy**

Closures enable private variables that are not accessible from outside.

```js
function privateCounter() {
let count = 0;

function incrementCount() {
return count++;
}

function getCount() {
return count;
}

return { incrementCount, getCount };
}

let counter = privateCounter();
console.log(counter.getCount()); // 0
counter.incrementCount();
console.log(counter.getCount()); // 1
```

2. **Maintain State**

Functions can remember their outer scope, allowing state to persist.

```js
function call() {
let time = 1;

function timer() {
return time++;
}

return timer;
}

let timer = call();
console.log(timer()); // 1
console.log(timer()); // 2
console.log(timer()); // 3
```

3. **Factorize Functions**

Closures help create functions that remember and use values across calls. `OR` Closures allow you to create customized functions.

```js
function multiplier(factor) {
return function (num) {
return factor * num;
};
}

let double = multiplier(2);
let triple = multiplier(3);

console.log(double(10)); // 20
console.log(triple(10)); // 30
```

### Disadvantages of Closures:

1. **Memory Consumption**

Closures retain references to their outer scope, which can increase memory usage if not managed well.

2. **Performance Issues**

Excessive use of closures may reduce performance due to increased memory usage.

3. **Debugging Challenges**

Closures can complicate debugging due to complex scope chains.

> Closure = (Inner) Function + Outer Variables (Preserved)

---

## ❕ Bonus Question

### ❓ Question: How can you optimize this expensive function?

You're given the following code:

```js
const clumsySquare = (num1, num2) => {
for (let i = 1; i <= 100000000; i++) {} // simulate heavy processing
return num1 * num2;
};
```

**Problem:**
- The function takes a long time to run due to the artificial delay.
- Calling it repeatedly with the **same arguments** will re-run the delay every time.

#### How can you make it faster?
**💡 Solution: Use Memoization**

> Memoization caches the result for a given set of inputs,
> so if you call the function again with the same arguments,
> it returns the cached result instantly, skipping recomputation.

**Memoized Version**
```js
function myMemoize(fn, context) {
const res = {}; // cache storage
return function (...args) {
const argsCache = JSON.stringify(args); // key from args
if (!res[argsCache]) {
console.log("Calculating...", args);
res[argsCache] = fn.apply(context || this, args);
}
return res[argsCache];
};
}
```
```js
// Apply Memoization to clumsySquare
const clumsySquare = (num1, num2) => {
for (let i = 1; i <= 100000000; i++) {} // simulate heavy work
return num1 * num2;
};

const memoizedSquare = myMemoize(clumsySquare);
console.time("First call");
console.log(memoizedSquare(9467, 7649)); // Slow: runs the loop
console.timeEnd("First call");

console.time("Second call");
console.log(memoizedSquare(9467, 7649)); // Fast: returns cached result
console.timeEnd("Second call");

```

- 🐌 Without memoization: Every call does expensive work
- ⚡ With memoization: Repeated calls are near-instant
- 👏 A simple yet powerful optimization using closures + lexical scope

---

## ❓ How Does Memory Management Work in JavaScript?

JavaScript handles memory using two main components:

- **Stack**: For static, fixed-size data (primitive types)
- **Heap**: For dynamic, complex data (reference types)

### Stack Memory (for Primitive Types)

**Stores:**

- Numbers, strings, booleans, `undefined`, `null`, `symbol`
- Local variables and function calls

**Characteristics:**

- Fast memory access (LIFO - Last In First Out)
- Memory is allocated linearly
- Values are copied (changes do not affect other variables)
- Automatically managed during function execution

```js
let num = 10; // Primitive stored in stack
let str = "Hello"; // Primitive stored in stack

function add(x, y) {
let sum = x + y; // Local variables stored in stack
return sum;
}
```

### Heap Memory (for Reference Types)

**Stores:**

- `Objects`, `arrays`, and `functions` (non-primitive types)

**Characteristics:**

- Memory allocated non-linearly
- Variables store references (not actual data)
- Slower access than stack
- Changes via one reference affect all others pointing to the same object

```js
let user = { name: "Ahad", age: 25 }; // Stored in heap
let arr = [1, 2, 3]; // Stored in heap

let obj1 = { value: 10 };
let obj2 = obj1; // Both point to the same object

obj1.value = 20;

console.log(obj2.value); // 20 (both refer to the same object)
```

### Garbage Collection

**JavaScript engines (like V8)** use automatic garbage collection to manage memory.

- Mark-and-Sweep Algorithm: Removes objects that are no longer accessible or referenced
- Unreachable memory is cleaned up to free space
- Developers don't manually manage memory — it's handled behind the scenes

> If an object or value is no longer reachable from the root (window or global), it's marked as garbage and removed.

![Stack vs Heap Memory](memory.png)

---

## ❓ What is the Difference between `var`, `let`, and `const` in JavaScript?

JavaScript provides three ways to declare variables: `var`, `let`, and `const`.

Each behaves differently in terms of:

- Scope
- Hoisting
- Redeclaration
- Reassignment
- Temporal Dead Zone (TDZ)
- Use cases

### var

- Function-scoped
- Can be redeclared and reassigned
- Hoisted and initialized with `undefined`
- Avoid in modern JavaScript due to confusing scope behavior

```js
function testVar() {
if (true) {
var x = 10;
}
console.log(x); // ✅ 10 (accessible outside the block)
}
testVar();
```

```js
// Hoisted and initialized with undefined
console.log(a); // ✅ undefined
var a = 5;
```

```js
// Can be redeclared in the same scope
var d = 100;
var d = 200; // ✅ No error
console.log(d); // 200
```

```js
// Can be reassigned
var g = 10;
g = 20; // ✅
console.log(g); // 20
```

```js
// No TDZ (initialized as undefined)
console.log(j); // ✅ undefined
var j = 5;
```

### let

- Block-scoped
- Cannot be redeclared in the same scope
- Can be reassigned
- Hoisted but not initialized (Temporal Dead Zone applies)

```js
function testLetConst() {
if (true) {
let y = 20;
}
console.log(y); // ❌ ReferenceError
}
testLetConst();
```

```js
// Hoisted but not initialized (TDZ)
console.log(b); // ❌ ReferenceError
let b = 10;
```

```js
// Cannot be redeclared in the same scope
let e = 1;
let e = 2; // ❌ SyntaxError: Identifier 'e' has already been declared
```

```js
// Can be reassigned
let h = 30;
h = 40; // ✅
console.log(h); // 40
```

```js
// TDZ applies (not accessible before declaration)
console.log(k); // ❌ ReferenceError
let k = 10;
```

### const

- Block-scoped
- Cannot be redeclared or reassigned
- Must be initialized at the time of declaration
- Also subject to Temporal Dead Zone

```js
function testLetConst() {
if (true) {
const z = 30;
}
console.log(z); // ❌ ReferenceError
}
testLetConst();
```

```js
// Hoisted but not initialized (TDZ)
console.log(c); // ❌ ReferenceError
const c = 15;
```

```js
// Cannot be redeclared in the same scope
const f = 3;
const f = 4; // ❌ SyntaxError
```

```js
// Cannot be reassigned
const i = 50;
i = 60; // ❌ TypeError: Assignment to constant variable
```

```js
// TDZ applies (not accessible before declaration)
console.log(l); // ❌ ReferenceError
const l = 15;
```

> ⚠️ However, `objects` and `arrays` declared with const can be mutated

```js
const obj = { name: "Ahad" };
obj.name = "Ali"; // ✅ Allowed
console.log(obj.name); // "Ali"
```

### Use Cases

| Keyword | Best Use |
| ------- | ---------------------------------------------------- |
| `var` | ❌ Avoid in modern code |
| `let` | ✅ When variable needs to change |
| `const` | ✅ For constants or when you don't want reassignment |

```js
const API_KEY = "123-abc"; // ✅ Use const for constants
let score = 0; // ✅ Use let if score may change
```

---

## ❓ What is Hoisting?

Hoisting is a JavaScript behavior where variable and function declarations are moved to the top of their scope during the creation phase, allowing them to be accessed before being defined in the code.

`OR`

**Hoisting** is JavaScript's behavior of moving **declarations** (not initializations) to the top of their scope before execution.

- Works with both variables and functions
- Variables declared with `var` are hoisted and set to `undefined`
- `let` and `const` are hoisted but not initialized (Temporal Dead Zone applies)
- Function declarations are fully hoisted

```js
greet(); // ✅ "Hi"

function greet() {
console.log("Hi");
}
```

```
console.log(a); // ✅ undefined
var a = 10;
```

```js
console.log(b); // ❌ ReferenceError
let b = 20;
```

> Only declarations are hoisted — initializations stay in place.

---

## ❓ What is the Behaviour of hoisting in case of `var`, `let`, and `const` in JavaScript?

| Declaration | Hoisted | Initialized | Scope | TDZ Applies |
| ----------- | ------- | ------------ | -------- | ----------- |
| var | ✅ Yes | ✅ undefined | Function | ❌ No |
| let | ✅ Yes | ❌ No | Block | ✅ Yes |
| const | ✅ Yes | ❌ No | Block | ✅ Yes |

```js
console.log(x); // ✅ undefined
var x = 10;
```

```js
console.log(y); // ❌ ReferenceError
let y = 20;
```

```js
console.log(z); // ❌ ReferenceError
const z = 30;
```

> `let` and `const` exist in memory during hoisting but cannot be accessed — this is called the Temporal Dead Zone (TDZ).

![alt text](hoisting.png)

---

## ❓ What is Temporal Dead Zone (TDZ)?

The **Temporal Dead Zone (TDZ)** is the time between variable hoisting and its declaration/initialization in code.

- Applies to `let` and `const`
- Does not apply to `var`
- Variable exists in memory but cannot be accessed yet

```js
x = 30; // ❌ ReferenceError
console.log(x); // ❌ ReferenceError
let x = 10; // ✅ x declared and initialized
```

> TDZ is "temporal" because it depends on the time of execution, not the position of code.

- Prevents accessing variables before intentional initialization
- Helps catch bugs in larger codebases

---

## ❓ What is Variable Shadowing?

**Variable shadowing** occurs when a variable declared in an inner scope (e.g., inside a block or function) has the **same name** as a variable in an outer scope. The inner variable **"shadows"** the outer one, making it inaccessible within that inner scope.

```js
let x = 0; // Outer variable (shadowed)
{
let x = 1; // Inner variable (shadows the outer x)
console.log(x); // ✅ 1 (refers to inner x)
}
console.log(x); // ✅ 0 (refers to outer x again)
```

> ⚠️ Shadowing only affects visibility within the inner scope.

```js
// Function Scope Example
let message = "Hello";

function greet() {
let message = "Hi"; // Shadows the outer 'message'
console.log(message); // ✅ "Hi"
}

greet();
console.log(message); // ✅ "Hello"
```

## ❓ What are Functions and there types in JavaScript?

Functions in JavaScript are blocks of reusable code that perform a specific task.

### Types of Functions in JavaScript:

- Normal (Named) Functions
- Arrow Functions
- Function Expressions
- Anonymous Functions
- First-Class Functions
- Call-Back Functions
- Pure Functions

---

## ❓ What is the Difference between Normal Function and Arrow Function?

1. Syntax

```javascript
// Normal Function
function add(a, b) {
return a + b;
}
```

```javascript
// Arrow Function
const add = (a, b) => a + b;

(a) => {
return a; // Explicit Return, Multi-Line
};

(a) => a; // Implicit Return, Single-Line

(a) => a; // Implicit Return, Multi-Line

(a, b) => a + b; // Multiple Parameters (Parentheses Required)
```

2. Return Behavior

- **Normal Functions**: Always require the `return` keyword to return a value.
- **Arrow Functions**: Allow implicit returns where the `return` keyword can be omitted for single-line expressions.

```javascript
// Normal Function
function multiply(a, b) {
return a * b; // Explicit Return
}

// Arrow Function
const multiply = (a, b) => a * b; // Implicit Return
```

3. Arguments Object

- **Normal Functions**: Have access to the `arguments` object, which contains the arguments passed to the function.
- **Arrow Functions**: Do not have their own `arguments` object.

```javascript
// Normal Function
function printArguments() {
console.log(arguments);
}
printArguments(1, 2, 3); // Output: [1, 2, 3]

// Arrow Function
const printArguments = () => {
console.log(arguments);
};
printArguments(1, 2, 3); // Error: 'arguments' is not defined
```

4. `this` Binding

- **Normal Functions**: Create their own `this` context, which depends on how the function is called.
- **Arrow Functions**: Do not create their own `this` context; they inherit `this` from the surrounding scope.

```javascript
// Normal Function
const obj1 = {
name: "Normal Function",
print: function () {
console.log(this);
},
};
obj1.print(); // Logs the obj1 object

// Arrow Function
const obj2 = {
name: "Arrow Function",
print: () => {
console.log(this);
},
};
obj2.print(); // Logs the global 'window' object (or 'undefined' in strict mode)
```

5. Constructors

- **Normal Functions**: Can be used as constructors with the `new` keyword.
- **Arrow Functions**: Cannot be used as constructors and will throw an error if used with `new`.

```javascript
// Normal Function as Constructor
function Person(name) {
this.name = name;
}
const person1 = new Person("Abdul Ahad"); // Works

// Arrow Function as Constructor
const Person = (name) => {
this.name = name;
};
const person2 = new Person("Abdul Ahad"); // Error: Person is not a constructor
```

6. Hoisting

- **Normal Functions**: Can be declared and are hoisted to the top of their scope.
- **Arrow Functions**: Cannot be accessed before initialization.

```javascript
// Normal Function
console.log(add(2, 3)); // Works
function add(a, b) {
return a + b;
}

// Arrow Function
console.log(subtract(5, 2)); // Error: Cannot access 'subtract' before initialization
const subtract = (a, b) => a - b;
```

7. Declaration

- **Normal Functions**: Can be declared using the `function` keyword.
- **Arrow Functions**: Must always be assigned to a variable or constant.

```javascript
// Normal Function Declaration
function greet() {
console.log("Hello!");
}

// Arrow Function Assignment
const greet = () => {
console.log("Hello!");
};
```

| **Feature** | **Normal Function** | **Arrow Function** |
| -------------------- | ---------------------------- | ------------------------------- |
| **Syntax** | `function add(a, b) { ... }` | `const add = (a, b) => { ... }` |
| **Return** | Explicit Return Required | Allows Implicit Return |
| **arguments Object** | Available | Not Available |
| **this Binding** | Creates Own `this` | Inherits `this` |
| **Constructor** | Can Be Used | Cannot Be Used |
| **Hoisting** | Fully Hoisted | Not Hoisted |
| **Declaration** | Using function keyword | Must Be Assigned to Variable |

---

## ❓ What is the Difference Between Function Expression and Anonymous Function?

1. Function Expression
A **Function Expression** is when you define a function and store it in a variable. You can use the variable to call the function later.

- The function expression can be:
- **Anonymous** (no name).
- **Named** (optional name).
- It’s **not hoisted**, so you cannot use it before defining it.

```javascript
// Function stored in a variable
let add = function (a, b) {
return a + b;
};
console.log(add(10, 20)); // Output: 30

// Function with a name stored in a variable
const multiply = function multiplyNumbers(a, b) {
return a * b;
};
console.log(multiply(10, 20)); // Output: 200
```

2. Anonymous Function
An **Anonymous Function** is a function without a name. It’s commonly used for one-time tasks, like in event handlers or `setTimeout`.

- Typically used when you don’t need to reuse the function elsewhere.

```javascript
setTimeout(function () {
console.log("Hello, I am an Anonymous Function!");
}, 1000);
```

3. Function Declaration
A **Function Declaration** is the traditional way to define reusable functions in JavaScript.

- Starts with the function keyword.
- Always has a name.
- Hoisted: You can call the function even before it’s defined in the code.

```javascript
function addNumbers(a, b) {
return a + b;
}
console.log(addNumbers(5, 15)); // Output: 20
```

| Feature | Function Expression | Anonymous Function | Function Declaration |
| --------------- | ------------------- | ------------------ | -------------------- |
| **Name** | Optional | Not present | Always present |
| **Hoisting** | No | No | Yes |
| **Reusability** | Yes | No | Yes |

---

## ❓ What is a First-Class Function?

In JavaScript, functions are treated like values. You can:

- Store them in variables.
- Pass them as arguments to other functions.
- Return them from other functions.
- Store them in objects and arrays.

This concept is called **First-Class Functions**.

1. Store a Function in a Variable
You can define a function and save it in a variable.

```javascript
let add = function (a, b) {
return a + b;
};
console.log(add(10, 20)); // Output: 30
```

2. Pass a Function as an Argument
Functions can be passed as arguments to other functions. This allows for dynamic behavior based on the function passed.

```javascript
function sayHello() {
return "Hello, ";
}
function executeFunction(callback) {
return callback() + "World";
}
console.log(executeFunction(sayHello)); // Output: Hello, World
```

3. Return a Function from Another Function
Functions can generate and return other functions, allowing for closures and reusable logic.

```javascript
function outerFunction() {
function innerFunction() {
return "Hello, World";
}
return innerFunction;
}
let inner = outerFunction();
console.log(inner()); // Output: Hello, World
```

4. Store Functions in Arrays and Objects
Functions can be stored as elements in arrays or as properties in objects. This makes it easy to organize and execute specific tasks.

```javascript
const operations = [
function (a, b) {
return a + b;
}, // Addition
function (a, b) {
return a * b;
}, // Multiplication
];

console.log(operations[0](2, 3)); // Output: 5
console.log(operations[1](2, 3)); // Output: 6
```

```javascript
const calculator = {
add: function (a, b) {
return a + b;
},
subtract: function (a, b) {
return a - b;
},
};

console.log(calculator.add(3, 2)); // Output: 5
console.log(calculator.subtract(3, 2)); // Output: 1
```

> First-Class Functions = Functions that can be treated like values

---

## ❓ What is a Callback Function?

> A callback function is a function passed as an argument to another function that gets executed later, often after some operation completes.

Use Cases:

- Asynchronous operations (setTimeout, API calls, DOM events)
- Functional programming patterns

```js
// Simple Callback Example
function greet(name, callback) {
console.log("Hi " + name);
callback();
}

function askQuestion() {
console.log("How are you?");
}

greet("Ahad", askQuestion);
// Output:
// Hi Ahad
// How are you?
```

```js
// setTimeout with Callback
setTimeout(function () {
console.log("Executed after 2 seconds");
}, 2000);
```

```js
// Array Method Example
const nums = [1, 2, 3];
nums.forEach(function (num) {
console.log(num * 2); // 2, 4, 6
});
```

```js
// Custom Callback Logic
function doSomething(callback) {
console.log("Doing something...");
callback("Task done");
}

doSomething(function (msg) {
console.log(msg); // Task done
});
```

### Why Use Callback Functions?

- To handle asynchronous logic
- To customize behavior dynamically
- To keep code flexible and modular

> A callback lets one function defer control to another function.

---

## ❓ What is a Pure Function?

A **pure function**:

- Depends only on its **input arguments**
- Has **no side effects**
- Always returns the **same output** for the same input

```js
// (Pure):
function add(a, b) {
return a + b;
}

// ❌ Not Pure:
let total = 0;
function addToTotal(a) {
total += a; // modifies external state (side effect)
}
```

---

## ❓ What is IIFE (Immediately Invoked Function Expression)?

An **IIFE (Immediately Invoked Function Expression)** is a JavaScript function that runs **immediately after it is defined**.

It’s a function that executes itself.

```js
(function () {
// code here
})();
```

### Types of IIFE

1. Anonymous Function IIFE
An IIFE without a name that runs immediately.

```js
(function () {
console.log("Hello, I am an Anonymous function IIFE!");
})();
```

**Arrow function version:**

```js
(() => console.log("Hello, I am an Anonymous function IIFE!"))(); // Alternatively, using an arrow function
```

2. Named Function IIFE
An IIFE that includes a function name.

```js
(function welcome() {
console.log("Hello, I am a Named function IIFE!");
})();
```

**Passing parameters:**

```js
(function add(a, b) {
console.log(a + b);
})(2, 3); // Output: 5
```

### Benefits of Using IIFE

1. Data Privacy
IIFE helps ensure data privacy by making variables declared inside the IIFE inaccessible from the outside world. This avoids polluting the global scope.

```javascript
(function () {
var message = "IIFE";
console.log(message);
})();
console.log(message); // Error: message is not defined
```

2. Return Value from IIFE
IIFE can be used to immediately return values from a function.

```javascript
var value = (() => 100)();
console.log(value); // Output: 100
```

3. Asynchronous IIFE
IIFE allows you to execute `async/await` operations immediately.

```javascript
const data = (async () => await fetch(url))();
```

### 🤔 How to Invoke IIFE Without Extra Parentheses?

Immediately Invoked Function Expressions (IIFE) usually require parentheses to wrap the function. However, you can avoid using extra parentheses by utilizing the `void` operator, which discards the result of the expression.

```javascript
// Using void to Avoid Extra Parentheses
void (function (dt) {
console.log(dt.toLocaleTimeString());
})(new Date());
```

---

## ❓ What is Currying? And Curied Function?

> Think of currying as a **type of closure**.

**Currying** is a functional programming technique in JavaScript where a function with multiple arguments is transformed into a series of functions that each take **one argument at a time**.

Instead of:

```js
f(a, b, c);
```

You write:

```js
f(a)(b)(c);
```

### Example: Normal vs Curried

❌ Normal Function

```js
function add(a, b) {
return a + b;
}

console.log(add(2, 3)); // Output: 5
```

✅ Curried Version

```js
function add(a) {
return function (b) {
return a + b;
};
}

console.log(add(2)(3)); // Output: 5
```

- The first function takes `a`
- Then returns another function that takes `b`
- Finally, returns the result of `a + b`

```js
// Real-World Example: Reusable Greetings
function greet(greeting) {
return function (name) {
return `${greeting}, ${name}!`;
};
}

const sayHi = greet("Hi");
console.log(sayHi("Ahad")); // Hi, Ahad!
console.log(sayHi("Zaid")); // Hi, Zaid!
```

> Reusability: You can create multiple greeting variations from the same curried base function.

```js
// Multiple-Level Currying
function sum(a) {
return function (b) {
return function (c) {
console.log(a, b, c);
return a + b + c;
};
};
}
console.log(sum(1)(2)(3)); // Output: 6
```

✅ Arrow Function Version

```js
const add = (a) => (b) => (c) => a + b + c;
console.log(add(1)(2)(3)); // Output: 6
```

```js
// Logging with Currying
let log = (time) => (type) => (msg) =>
`At ${time.toLocaleString()}: severity ${type} => ${msg}`;

console.log(log(new Date())("error")("power not sufficient"));

let logNow = log(new Date());
console.log(logNow("warning")("temp high"));

let logErrorNow = log(new Date())("error");
console.log(logErrorNow("unknown error"));
```

```js
// Currying with Operation Type
function op(operation) {
return function (a) {
return function (b) {
return operation === "add" ? a + b : a - b;
};
};
}

const add3 = op("add")(3);
const sub3 = op("sub")(3);
const add = op("add");

console.log(add3(6)); // 9
console.log(sub3(6)); // -3
console.log(add(1)(2)); // 3
```

> **Important Note:**
> Currying does not mean calling multiple parameters normally.

```js
// ❌ This is NOT currying
function fakeCurrying(a, b, c) {
return a + b + c;
}
```

> Currying means returning functions for each parameter.

### Infinite Currying
- Keep returning functions until a call is made with **no argument**, at which point the final result is returned.

```js
function add(a) {
return function(b) {
if (b !== undefined) {
return add(a + b);
}
return a;
};
}
```
```js
add(2)(3)(4)(5)(); // Output: 14
```

#### One Liner Version
```js
const add = a => b => b !== undefined ? add(a + b) : a;
```

---

## ❓ What are Functions Behaviour in JavaScript?

### 1. Functions are First-Class Objects

- In JavaScript, functions are **objects**.
- This means they can:
- Be stored in variables
- Be passed as arguments
- Be returned from other functions
- Have **properties** like any object

```js
function sayHi(greet) {
return greet;
}

sayHi.name; // "sayHi" ➡️ function name
sayHi.length; // 1 ➡️ number of parameters

sayHi.count = 0; // You can add custom properties!
sayHi.count++;
console.log(sayHi.count); // 1
```

### 2. Function Declaration vs Function Expression

| Type | Hoisted | Callable Before Declaration |
| -------------------- | ------- | --------------------------- |
| Function Declaration | ✅ Yes | ✅ Yes |
| Function Expression | ❌ No | ❌ No |

```js
sayHi(); // ✅ Works
function sayHi() {
return "Hi!";
}

sayHello(); // ❌ ReferenceError
let sayHello = function () {
return "Hello!";
};
```

### 3. Constructor Functions

Functions can be called with `new` to create custom objects.

```js
function Person(name) {
this.name = name;
}

const p = new Person("Abdul Ahad");
console.log(p.name); // "Abdul Ahad"
```

### 4. Named Function Expression (NFE)

Helpful for self-reference even if the variable is reassigned.

```js
let sayHello = function fx(user) {
if (user) return "Hello " + user;
else return fx("Anonymous"); // Recursive call using name fx
};

let sayHi = sayHello;
sayHello = null;

console.log(sayHi()); // "Hello Anonymous"
```

### 5. Decorators (Function Wrappers)

A design pattern to enhance or modify a function without changing its original code.

### Memoization Example

```js
function heavy(x) {
console.log(x + ":heavy");
return x + ":heavy";
}

function memoized(fx) {
let map = new Map();
return function (x) {
if (map.has(x)) return map.get(x);
let val = fx(x);
map.set(x, val);
return val;
};
}

const memoHeavy = memoized(heavy);

memoHeavy(2); // logs and returns
memoHeavy(2); // returns from cache
```

> Use case: Caching expensive operations like API calls, Fibonacci, etc.

### 🧨 Problem: `this` is lost in memoization

```js
let task = {
name: "demo",
heavy(x) {
console.log(x + ":heavy:" + this.name);
return x + ":heavy:" + this.name;
},
};

task.memoizedHeavy = memoized(task.heavy);
task.memoizedHeavy(1); // ❌ undefined — `this` is lost
```

### ❓ Why does it fail?

- In **non-strict mode**, `this` defaults to `window` (global).
- In **strict mode**, `this` is `undefined`.
- `task.heavy` loses its context when passed as a callback.

### Solution: Use `.call(this, x)` inside wrapper

```js
function memoized(fx) {
let map = new Map();
return function (x) {
if (map.has(x)) return map.get(x);
let val = fx.call(this, x); // ✅ Preserve original `this`
map.set(x, val);
return val;
};
}
```

Now:

```js
task.memoizedHeavy = memoized(task.heavy);
task.memoizedHeavy(1); // ✅ Works — "1:heavy:demo"
```

---

## ❓ What is Debounce and Throttle?

These are **performance optimization patterns**, especially useful for handling **frequent events** like:

- Typing (`keyup`)
- Scrolling
- Resizing
- Mouse movement

Both are types of **decorators** (wrappers) that **control the rate** of function execution.

### 🕐 1. **Debounce**

> ✅ Only run the function after the user has stopped triggering it for a fixed time.
> A technique to delay the execution of a function until a specified time has passed without calling it again.

### Real-World Analogy:

- Typing in a search box...
- You **don’t want to search** on every key press — only after the user **pauses** typing (say, for 1 second).

### How It Works:

- Each call **resets** the timer.
- Only the **last call** after a pause is executed.

```js
function debounce(fx, time) {
let id = null;

return function (x) {
if (id) clearTimeout(id); // Cancel previous timer
id = setTimeout(() => {
fx(x); // Only call after pause
id = null;
}, time);
};
}
```

```js
let count = 1;
function showCount() {
console.log(count++);
}

const showCountD = debounce(showCount, 2000);

setTimeout(showCountD, 1000);
setTimeout(showCountD, 1500);
setTimeout(showCountD, 2000);
setTimeout(showCountD, 2500);
setTimeout(showCountD, 5000); // ✅ Only final call runs after 2s pause
```

### DOM Example (Live Search Input):

```
const el = document.getElementById('text1');
const logo = document.getElementById('text-output1');

el.addEventListener(
'keyup',
debounce(function (e) {
logo.innerText = e.target.value;
}, 1000)
);
```

```html


```

### Real-Life Analogy:

> 👧 A kid tells her mom: "Give me chocolate!"
>
> 🧓 Mom says: _"Be quiet for 10 minutes, then I will!"_
>
> ❌ If the kid speaks again — the timer resets.
>
> ✅ Only if quiet for 10 mins straight, she gets chocolate.

| Feature | Debounce |
| ------------- | -------------------------------------------- |
| Trigger logic | After inactivity pause ⏸️ |
| Use case | Search inputs, form validations, live typing |
| Key behavior | Cancels previous calls, runs only the last |

### 🚦 2. **Throttle**

> Run the function at most once in a specified time window — even if it’s triggered many times.

> A technique to limit function execution to once per given time period, even if called many times.

### Real-World Analogy:

You are scrolling rapidly, but you only want to run a function **every 100ms** — no matter how fast the user rolls.

### How It Works:

- Once triggered, it **ignores repeated calls** until time expires.

```js
function throttle(fx, time) {
let id = null;
let arg = [];

return function (x) {
arg[0] = x;
if (!id) {
id = setTimeout(() => {
fx(arg[0]);
id = null; // Reset for next window
}, time);
}
};
}
```

```js
let count = 1;
function showCount() {
console.log(count++);
}

const showCountT = throttle(showCount, 2000);

setTimeout(showCountT, 1000);
setTimeout(showCountT, 1500);
setTimeout(showCountT, 2000);
setTimeout(showCountT, 2500);
setTimeout(showCountT, 5000); // ✅ Runs once every 2 seconds
```

### DOM Example (Scroll Event):

```
function sayHi() {
console.log("hi");
}

document.addEventListener('scroll', throttle(sayHi, 1000));
```

### Real-Life Analogy:

> 👧 A kid tells her mom: "I want food!"
>
> 🧓 Mom says: _"Okay, but you'll only get it **once every 10 minutes**, no matter how many times you ask."_
>
> 🕐 Kid keeps asking at 3 min, 5 min, 8 min...
>
> ❌ Mom ignores all in-between requests
>
> ✅ At the **10-minute mark**, she gives food — **only once**
>
> Then timer starts again...

🗣️ **Meaning:**

Even if an event happens **repeatedly**, it will **only be handled at regular intervals**, not every time it fires.

| Feature | Throttle |
| ------------- | ------------------------------------------ |
| Trigger logic | At most once per time window ⏱️ |
| Use case | Scroll, resize, drag, mousemove |
| Key behavior | Ignores repeated triggers during wait time |

| Concept | Real-Life Analogy |
| --------------- | ------------------------------------------------------------------------------------- |
| **Debounce** ⏳ | _"Stay quiet for 10 minutes, then you'll get chocolate. If you speak, timer resets."_ |
| **Throttle** 🚦 | _"Ask for food all you want, you'll only get it once every 10 minutes."_ |

### Debounce vs Throttle — Quick Comparison

| Feature | Debounce 🧯 | Throttle 🚦 |
| --------------- | ------------------------ | ------------------------- |
| Triggered when | After inactivity timeout | Once per fixed interval |
| Use case | Typing, search inputs | Scroll, resize, mousemove |
| Cancel previous | ✅ Yes | ❌ No |
| Skips calls? | ✅ All before pause | ✅ All during interval |

### Bonus: Arrow Function Differences

| Feature | Arrow Functions (`=>`) | Normal Functions |
| --------------------- | -------------------------- | ---------------- |
| `this` binding | ❌ Lexical (no own `this`) | ✅ Own `this` |
| `arguments` object | ❌ Not available | ✅ Available |
| Used as constructor? | ❌ No (`new` not allowed) | ✅ Yes |
| Has `name` & `length` | ✅ Yes | ✅ Yes |

---

## ❓ What are Iterables & Generators in JavaScript?

### What are Iterables?

> Objects that can be looped through one by one using `for...of` or the spread `...` operator.

`OR`

> An object is **iterable** if it implements the **`Symbol.iterator()`** method that returns an **iterator object**.

**Built-in Iterables:**

- Arrays ✅
- Strings ✅
- Maps & Sets ✅

### What is an Iterator?

- An object with a `.next()` method.
- `.next()` returns an object:

```js
{ value: any, done: boolean }
```

- `done: true` means iteration finished.

```js
const iterator = [10, 20][Symbol.iterator]();

console.log(iterator.next()); // { value: 10, done: false }
console.log(iterator.next()); // { value: 20, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
```

````

### How to Create a Custom Iterable?

- Implement `[Symbol.iterator]` method returning an iterator.
- Iterator has a `.next()` method returning `{ value, done }`.

```js
const range = {
start: 1,
end: 3,
[Symbol.iterator]() {
let current = this.start;
const end = this.end;
return {
next() {
if (current <= end) {
return { value: current++, done: false };
} else {
return { done: true };
}
}
};
}
};

for (const num of range) {
console.log(num); // 1, 2, 3
}
````

What is a Generator?

- A special function that can pause (`yield`) and resume.
- Implements iterable and iterator protocols automatically.
- Simplifies iterator creation.

Syntax and Example:

```js
function* genFunc() {
yield 1;
yield 2;
yield 3;
}
const gen = genFunc();

console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
```

### Why Use Generators?

- Lazy evaluation: produce values on demand.
- Can create infinite sequences safely.
- Useful for asynchronous flows.
- Cleaner syntax for iterators.

### Can Generators Create Infinite Sequences?

Yes, using loops inside the generator:

```js
function* infiniteCounter() {
let i = 0;
while (true) {
yield i++;
}
}
const counter = infiniteCounter();

console.log(counter.next().value); // 0
console.log(counter.next().value); // 1
```

> ⚠️ Use carefully to avoid infinite loops.

### Using Generators with for...of and Spread

Generators are iterable:

```js
function* nums() {
yield 1;
yield 2;
yield 3;
}

console.log([...nums()]); // [1, 2, 3]
```

### Generator Composition (yield\*)

Use `yield*` to delegate to another generator:

```js
function* range(start, end) {
for (let i = start; i <= end; i++) yield i;
}

function* composed() {
yield* range(1, 3);
yield* range(100, 102);
}

console.log([...composed()]); // [1, 2, 3, 100, 101, 102]
```

### Passing Values to Generators

You can send values back into a generator via `.next(value)`:

```js
function* gen() {
const val = yield "first yield";
console.log("Received:", val);
}
const g = gen();

g.next(); // Start generator, yields 'first yield'
g.next("Hello"); // Logs 'Received: Hello'
```

| Feature | Iterable | Iterator | Generator |
| ------------------------------ | --------------------------- | -------------------- | ------------------------ |
| Implements `Symbol.iterator()` | Yes (returns iterator) | Optional | Yes (built-in) |
| Has `.next()` method | No | Yes | Yes |
| Can be looped by `for...of` | Yes | No | Yes |
| Purpose | Provides iterable interface | Steps through values | Creates iterators easily |
| Infinite sequence | Usually No | Yes (manual control) | Yes |

---

## ❓ What is an Object in JavaScript?

An **object** in JavaScript is a variable that can store **multiple values** as **key-value pairs**.

Objects are great for grouping related data and behavior.

```js
let person = {
name: "Ahad Ali",
age: 30,
city: "New York",
};

console.log(person.name); // Output: Ahad Ali
```

- Properties store data.
- Methods are functions stored in properties.
- Keys are strings (or Symbols), values can be any data type.

### Object References & Nesting

**Object References**

```js
let person = { name: "Ahad Ali" };
let human = person;

human.name = "Abdul Ahad";
console.log(person.name); // Abdul Ahad
```

- Objects are assigned by **reference**, not copied.
- Changing one reference affects the other.

**Nesting of Objects**

Objects can hold other objects:

```js
let person = {
name: "Ahad Ali",
address: { city: "Delhi", state: "Delhi" },
};

console.log(person.address.city); // Delhi
```

---

## ❓ What is the Difference between Deep Copy and Shallow Copy in JavaScript?

### Shallow Copy

A **shallow copy** duplicates only the top-level structure of an object or array.
It **does not clone nested objects or arrays**, meaning they are still **shared by reference**.

- ✅ Top-level properties copied
- ❌ Nested objects remain linked (reference)

```js
// Reference Copy Example
let person = { name: "Abdul Ahad", address: { city: "Delhi" } };
let newPerson = { ...person };

newPerson.address.city = "Mumbai";
console.log(person.address.city); // Mumbai ❗ (affected)
```

```js
// Primitive Copy Example
newPerson.name = "Ahad Ali";
console.log(person.name); // Abdul Ahad ✅ (not affected)
```

| Type | Copied As | Affects Original? |
| --------- | ------------ | ----------------- |
| Primitive | By Value | ❌ No |
| Object | By Reference | ✅ Yes |

```js
// Shallow Copy in Action
const original = { name: "Mudassir", details: { age: 25, city: "New York" } };

// Shallow copy using spread operator
const shallowCopy = { ...original };

shallowCopy.name = "Ahsan";
shallowCopy.details.age = 30;

console.log(original.details.age); // 30 ❗
console.log(shallowCopy.details.age); // 30
```

### What is Deep Copy?

A **deep copy** creates a **fully independent copy** of the object, including **all nested objects and arrays**.

- ✅ Changes in the copy **do not affect** the original
- ✅ Useful for safely working with complex data structures

### 1. Deep Copy Using `JSON.stringify()` + `JSON.parse()`

```js
let person = {
name: "Abdul Ahad",
address: { city: "Delhi" },
};

let deepCopy = JSON.parse(JSON.stringify(person));
```

⚠️ Limitations:

- ❌ Doesn’t copy `undefined`, `functions`, `Date`, `Map`, `Set`, circular refs

### 2. Deep Copy Using `structuredClone()` (Modern Browsers)

```js
let person = {
name: "Abdul Ahad",
address: { city: "Delhi" },
};

let deep = structuredClone(person);
```

```js
// Deep Copy in Action
const original = { name: "Alice", details: { age: 25, city: "New York" } };

// Deep copy using JSON methods
const deepCopy = JSON.parse(JSON.stringify(original));

deepCopy.name = "Ahsan";
deepCopy.details.age = 30;

console.log(original.details.age); // 25 ✅
console.log(deepCopy.details.age); // 30
```

| Feature | Shallow Copy | Deep Copy |
| ----------------------- | ----------------------------- | -------------------------------------------------------- |
| What it copies | Only top-level properties | All levels (including nested objects) |
| Nested references | ❌ Still point to original | ✅ Completely independent |
| Affects original? | ✅ Yes (for nested data) | ❌ No |
| Copy method example | `const copy = { ...obj }` | `JSON.parse(JSON.stringify(obj))` or `structuredClone()` |
| Supports functions? | ✅ Yes | ❌ No (if using JSON methods) |
| Supports circular refs? | ✅ Yes (manual or modern API) | ✅ Yes (`structuredClone()`) only |

---

## ❕ Bonus Questions

### Delete keyword in functions

```js
const func = (function (a) {
delete a;
return a;
})(5);
console.log(func); // 5
```

✅ **Explanation**: `delete` only removes properties from **objects**. `a` is a local function argument (not an object property), so `delete a` does nothing.

### Delete property from object

```js
const user = {
name: "Ahad Ali",
age: 24,
"like this video": true,
};
delete user["like this video"];
console.log(user);
```

✅ **Output**:

```js
{ name: 'Ahad Ali', age: 24 }
```

✅ **Explanation**: `delete` works on object properties. This successfully removes the dynamic key.

### Dynamic object keys

```js
const property = "firstName";
const name = "Ahad Ali";
const user = {
[property]: name,
};
console.log(user.firstName); // "Ahad Ali"
```

✅ **Explanation**: Computed property names using square brackets allow dynamic key assignment.

### Looping over object keys

```js
const user = {
name: "Ahad Ali",
age: 24,
isTotallyAwesome: true,
};
for (key in user) {
console.log(user[key]);
}
```

✅ **Output**:

```js
Ahad Ali
24
true
```

✅ **Explanation**: `for...in` loops through enumerable properties.

### Duplicate keys in object

```js
const obj = {
a: "one",
b: "two",
a: "three",
};
console.log(obj);
```

✅ **Output**:

```js
{ a: 'three', b: 'two' }
```

✅ **Explanation**: Last key declaration wins. Earlier one is overwritten.

### How to Multiply object values by 2?

```js
let nums = {
a: 100,
b: 200,
title: "My nums",
};
function multiplyByTwo(obj) {
for (key in obj) {
if (typeof obj[key] === "number") {
obj[key] *= 2;
}
}
}
multiplyByTwo(nums);
console.log(nums);
```

✅ **Output**:

```js
{ a: 200, b: 400, title: 'My nums' }
```

✅ **Explanation**: Only numeric properties are modified.

### Object keys as objects

```js
const a = {};
const b = { key: "b" };
const c = { key: "c" };
a[b] = 123;
a[c] = 456;
console.log(a[b]);
```

✅ **Output**:

```js
456;
```

✅ **Explanation**: Object keys are converted to strings. Both `b` and `c` become `"[object Object]"`, so the second assignment overrides the first.

### JSON.stringify with selected keys

```js
const settings = {
username: "Ahad",
level: 19,
health: 90,
};
const data = JSON.stringify(settings, ["level", "health"]);
console.log(data);
```

✅ **Output**:

```js
{"level":19,"health":90}
```

✅ **Explanation**: Second argument is a replacer array - it picks only specified keys.

### Arrow function vs regular method in object

```js
const shape = {
radius: 10,
diameter() {
return this.radius * 2;
},
perimeter: () => 2 * Math.PI * this.radius,
};
console.log(shape.diameter());
console.log(shape.perimeter());
```

✅ **Output**:

```js
20;
NaN;
```

✅ **Explanation**:

- `diameter()` is a regular method — `this` refers to `shape`
- `perimeter` is an arrow function — `this` does **not** refer to `shape`, but to outer scope

### Destructuring nested object properties

```js
const user = {
name: "Ahad Ali",
age: 24,
fullName: {
first: "Ahad",
last: "Ali",
},
};

const {
fullName: { first },
} = user;
console.log(first); // "Ahad"
```

✅ **Explanation**: We're using **nested destructuring** to extract the `first` key from `fullName`. The variable `first` is available directly.

### Object references and mutation

```js
let c = { greeting: "Hey!" };
let d;
d = c;
c.greeting = "Hello";
console.log(d.greeting); // "Hello"
```

✅ **Explanation**: `c` and `d` reference the same object in memory. Updating one reflects in the other.

### Object comparison

```js
console.log({ a: 1 } == { a: 1 }); // false
console.log({ a: 1 } === { a: 1 }); // false
```

✅ **Explanation**: Objects are only equal by **reference**, not by structure or value. These are two different object instances.

### Reference kept in array after setting object to null

```js
let person = { name: "Abdul Ahad" };
const members = [person];
person = null;
console.log(members);
```

✅ **Output**:

```js
[{ name: "Abdul Ahad" }];
```

✅ **Explanation**: The array still holds a reference to the original object, even after `person = null`.

### Object property set to null (not the object itself)

```js
let person = { name: "Abdul Ahad" };
const members = [person];
person.name = null;
console.log(members);
```

✅ **Output**:

```js
[{ name: null }];
```

✅ **Explanation**: Since both `person` and `members[0]` refer to the same object, changes in one reflect in the other.

### Spread and default parameter reference behavior

```js
const value = { number: 10 };
const multiply = (x = { ...value }) => {
console.log((x.number *= 2));
};

multiply(); // 20
multiply(); // 20
multiply(value); // 20
multiply(value); // 40
```

✅ **Explanation**:

- `{ ...value }` creates a **new copy** each time, so default calls don’t affect each other.
- When `value` is passed directly, mutation affects the same object.

### Object mutation vs reassignment

```js
function changeAgeAndReference(person) {
person.age = 25;
person = {
name: "Abdul Ahad",
age: 50,
};
return person;
}

const personObj1 = {
name: "Ahad Ali",
age: 30,
};

const personObj2 = changeAgeAndReference(personObj1);
console.log(personObj1); // { name: 'Ahad Ali', age: 25 }
console.log(personObj2); // { name: 'Abdul Ahad', age: 50 }
```

✅ **Explanation**:

- `person.age = 25` mutates the original object
- `person = {...}` creates a **new object**, not affecting the original

---

## ❓ What are Prototypes & Prototypal Inheritance in JavaScript?

### What are Prototypes in JavaScript?

> Every object in JavaScript has a hidden link to another object called its prototype.

If JavaScript doesn’t find a property on an object, it **goes to its prototype** to look for it.

### Real-Life Analogy

Imagine you're asking your younger brother for a pen.

- Your brother is the object.
- Dad is the prototype.
- JS will go up the chain (to Dad) until it finds the pen (property).

### What is Prototypal Inheritance?

Prototypal inheritance allows one object to inherit properties and methods from another.

- JavaScript uses **objects extending other objects**.

```js
let animal = { eats: true };
let dog = { barks: true };

dog.__proto__ = animal;

console.log(dog.barks); // true
console.log(dog.eats); // true (inherited from animal)
```

✅ `dog.__proto__`→ points to `animal`

```js
// Prototype Chain
let animal = {
eats: true,
walks: function () {
return "walks";
},
};

let dog = { barks: true };
dog.__proto__ = animal;

let myDog = { name: "sifu" };
myDog.__proto__ = dog;

console.log(myDog.name); // sifu
console.log(myDog.barks); // true
console.log(myDog.walks()); // walks
```

- **Chain:** myDog → dog → animal → Object.prototype → null

### ⚠️ proto vs [[Prototype]]

**proto** is a getter/setter (not recommended)

✅ Preferred:

```js
Object.getPrototypeOf(obj);
Object.setPrototypeOf(obj, prototypeObj);
```

### Inherited Methods Behavior

```js
let dog = { barks: true };
let animal = {
eats: true,
walks: () => "walks",
};

dog.__proto__ = animal;

let myDog = { name: "sifu" };
myDog.__proto__ = dog;
myDog.walks = () => "walks slowly";

console.log(myDog.walks()); // walks slowly
console.log(dog.walks()); // walks
```

### Property Lookup Rules

- Check own property first
- Then prototype
- Then up the chain

```js
let obj = { a: 1 };
console.log(obj.a); // 1
console.log(obj.toString()); // from Object.prototype
```

---

## ❓ What are Polyfills and Transpilers in JavaScript?

A **polyfill** is a piece of code that adds support for modern JavaScript features
in **older browsers** that don’t support them yet.

- Think of it like a **backup version** of a modern feature — written using older code
so that it can still work in older environments.

- Polyfills are **custom implementations** of modern features.
- They check if a feature exists — and if not, define it manually.
- Most polyfills extend built-in objects like `Array`, `Object`, `Promise`, etc.

### Common Polyfill Interview Tasks

- `forEach()`
- `map()`
- `filter()`
- `reduce()`
- `bind()`

### ✅ Implementing `forEach()` from scratch

```js
Array.prototype.myForEach = function (callback) {
for (var i = 0; i < this.length; i++) {
callback(this[i], i, this); // currentValue, index, array
}
};

let arr = ["Moosetape", "BDFU", "Godzilla"];
arr.myForEach((item) => console.log(item));
```

### ✅ Implementing map() from scratch

```js
Array.prototype.myMap = function (callback) {
var arr = [];
for (var i = 0; i < this.length; i++) {
arr.push(callback(this[i], i, this));
}
return arr;
};

let arr = ["Moosetape", "BDFU", "Godzilla"];
const result = arr.myMap((item) => item.toUpperCase());
console.log(result); // ["MOOSETAPE", "BDFU", "GODZILLA"]
```

### ✅ Implementing filter() from scratch

```
Array.prototype.myFilter = function (callback, context) {
let arr = [];
for (var i = 0; i < this.length; i++) {
if (callback.call(context, this[i], i, this)) {
arr.push(this[i]);
}
}
return arr;
};

let albums = [
{ name: "Moosetape", songs: 20 },
{ name: "BDFU", songs: 7 },
{ name: "Godzilla", songs: 11 },
];

let result = albums.myFilter(function (album) {
return album.songs > 10;
});

console.log(result); // [{ name: "Moosetape", songs: 20 }, { name: "Godzilla", songs: 11 }]
```

### ✅ Implementing reduce() from scratch

```js
Array.prototype.myReduce = function (callback, initialValue) {
let accumulator = initialValue === undefined ? undefined : initialValue;

for (var i = 0; i < this.length; i++) {
if (accumulator !== undefined) {
accumulator = callback.call(undefined, accumulator, this[i], i, this);
} else {
accumulator = this[i];
}
}

return accumulator;
};

let arr = ["Moosetape", "BDFU", "Godzilla"];
let result = arr.myReduce(function (a, b) {
return a + " " + b;
}, "Tape -");

console.log(result); // Tape - Moosetape BDFU Godzilla
```

### ✅ Implementing bind() from scratch

```js
let name = {
first: "Ahad ",
last: "Ali",
};

let display = function () {
console.log(`${this.first} ${this.last}`);
};

Function.prototype.myBind = function (...args) {
let obj = this; // original function (display)
return function () {
obj.call(args[0]);
};
};

let displayMe = display.myBind(name);
displayMe(); // Ahad Ali
```

A **transpiler** converts modern JavaScript (ES6+) into older JavaScript (ES5)
for compatibility with older browsers.

Common tools:
- Babel
- TypeScript

Used in most front-end frameworks like React, Vue, Angular, etc.

---

## ❓ What are Classes in JavaScript?

> A class is a cleaner, more familiar way to write code that uses prototypal inheritance in JavaScript.

It’s just **syntactic sugar** — a nicer way to do the same thing you were already doing using functions and prototypes — but it also adds **extra features** like:

- `get` and `set` methods
- non-enumerable methods
- auto `strict mode`
- better error handling

### Old Way (Prototypes):

```js
function User(name) {
this.name = name;
}

User.prototype.sayHi = function () {
return this.name;
};

let user = new User("Ahad");
user.sayHi(); // Ahad
```

### 🆕 New Way (Class):

```js
class User {
constructor(name) {
this.name = name;
}

sayHi() {
return this.name;
}
}

let user = new User("Ahad");
user.sayHi(); // Ahad
```

- Both ways work the same under the hood: `sayHi` is placed in the prototype.

### Class is always in 'strict mode'

```js
// In normal JS
x = 5; // works

// In class environment (strict mode)
class Something {
constructor() {
x = 5; // ❌ ReferenceError
}
}
```

### Class Getter and Setter

```js
class User {
constructor(first, last) {
this.first = first;
this.last = last;
}

get fullName() {
return this.first + " " + this.last;
}

set fullName(name) {
[this.first, this.last] = name.split(" ");
}
}

let user = new User("Ahad", "Ali");
console.log(user.fullName); // Ahad Ali

user.fullName = "Abdul Ahad Cena";
console.log(user.first); // Abdul Ahad
console.log(user.last); // Cena
```

> ✅ Clean way to access derived/computed properties

### `this` Problem in Classes

```js
class Button {
constructor(value) {
this.value = value;
}

click() {
console.log(this.value);
}
}

let button = new Button("Play");

// ❌ Problem
setTimeout(button.click, 1000); // undefined
```

#### ❓ Why this fails:

- When passing button.click into `setTimeout`, the this context is lost.

### 3 Ways to Fix the this Problem

1. Arrow function:

```js
setTimeout(() => button.click(), 1000);
```

2. Bind:

```js
setTimeout(button.click.bind(button), 1000);
```

3. Use class field:

```js
class Button {
constructor(value) {
this.value = value;
}

click = () => {
console.log(this.value);
};
}

let button = new Button("Play");
setTimeout(button.click, 1000); // ✅ Works
```

---

## ❓ What is Inheritance and Static method and access specifier in JS?

Inheritance allows a class (Child) to inherit properties and methods from another class (Parent) using the `extends` keyword.

> JavaScript uses prototypal inheritance under the hood, but class syntax simplifies it.

### Basic Class Inheritance

```js
class Shape {
constructor(name) {
this.name = name;
}

displayShape() {
return "Shape " + this.name;
}
}

class Rectangle extends Shape {}

const rect1 = new Rectangle("Rect 1");
console.log(rect1.displayShape()); // Shape Rect 1
```

- Even without a constructor in Rectangle, the parent constructor is called automatically.

### Custom Constructor in Child Class

If the child class has its own constructor, you must call super() to initialize the parent:

```js
class Rectangle extends Shape {
constructor(name, width, height) {
super(name); // Call parent constructor
this.width = width;
this.height = height;
this.area = width * height;
}
}

const rect2 = new Rectangle("Rect 2", 10, 20);
console.log(rect2.area); // 200
```

- super() must be the first line in the child constructor.

### Prototype Chain

Under the hood, inheritance creates this structure:

```
rect1 → Rectangle.prototype → Shape.prototype → Object.prototype

```

### Static Methods

A **static method** belongs to the class itself, not its instances.

```js
class Shape {
constructor(name, area) {
this.name = name;
this.area = area;
}

static areEqual(shape1, shape2) {
return shape1.name === shape2.name && shape1.area === shape2.area;
}
}

const s1 = new Shape("square", 100);
const s2 = new Shape("square", 100);

console.log(Shape.areEqual(s1, s2)); // true
```

> 🔒 You cannot call a static method from an instance:

```
s1.areEqual // ❌ Error
```

- Static methods are useful for utility/helper logic.

### Access Modifiers in JS (Public, Protected, Private)

JavaScript supports access control through naming conventions and private syntax.

### 1️⃣ **Public Properties** (Default)

```
class User {
constructor(name) {
this.name = name;
this.type = "admin";
}
}

const user = new User("Ahad");
console.log(user.name); // Ahad
user.type = "normal"; // Directly accessible
```

### 2️⃣ **Protected (Convention)** using `_underscore`

JavaScript doesn't have real protected, but we use \_ to indicate internal use.

```
class User {
constructor(name) {
this.name = name;
this._type = "admin";
}

get type() {
return this._type;
}

set type(val) {
if (val === "admin" || val === "normal") {
this._type = val;
} else {
throw new Error("Only 'admin' or 'normal' allowed");
}
}
}

const user = new User("Ahad");
user.type = "normal"; // ✅ setter used
console.log(user.type); // normal
```

### 3️⃣ **Private Properties** (Truly Private using #)

Introduced in ES2022+

```js
class User {
#type = "admin";

constructor(name) {
this.name = name;
}

get type() {
return this.#type;
}

set type(val) {
if (val === "admin" || val === "normal") {
this.#type = val;
} else {
throw new Error("Only 'admin' or 'normal' allowed");
}
}
}

const user = new User("Ahad");
user.type = "normal";
console.log(user.type); // normal

// ❌ Error: cannot access private field
// console.log(user.#type);
```

- Use for true encapsulation and safety.

### `instanceof`

Used to check inheritance relationships:

```
rect1 instanceof Rectangle // true
rect1 instanceof Shape // true

```

---

## ❓ What is the Difference Constructor Function and Factory Function?

| Feature | Constructor Function | Factory Function |
|----------------|-----------------------------|--------------------------------|
| Syntax | Uses `new` keyword | Regular function |
| `this` usage | Uses `this` internally | Returns object directly |
| Reusability | Supports prototypes | Uses closures or literals |

```js
// Constructor Function
function Person(name) {
this.name = name;
}
let p1 = new Person("Ahad");

// Factory Function
function createPerson(name) {
return { name };
}
let p2 = createPerson("Ahad");
```

---

## ❓ What is an Array in JavaScript?

An **array** in JavaScript is a special type of variable that can hold **multiple values** at once.

Arrays are used to store collections of data, such as:

- A list of numbers
- A list of strings
- A mix of data types (number, string, object, boolean, etc.)

- Zero-based indexing (starts from 0)
- Dynamically sized
- Can hold any type of data

```js
let numbers = [1, 2, 3, 4, 5];
console.log(numbers[0]); // Output: 1
```

```js
let mixedArray = [
42,
"Ahad",
true,
{ role: "dev" },
function () {
return "hello";
},
];
console.log(mixedArray[3].role); // Output: "dev"
console.log(mixedArray[4]()); // Output: "hello"
```

### Array Methods:

| Method | Description |
| ----------- | ------------------------------------ |
| `push()` | Add element to end |
| `pop()` | Remove last element |
| `shift()` | Remove first element |
| `unshift()` | Add element to start |
| `map()` | Transform items and return new array |
| `filter()` | Filter items based on condition |
| `forEach()` | Run a function for each item |

---

## ❓ What is the Difference between `forEach()`, `map()`, `filter()`, `reduce()`, `find()`, `some()`, `every()` in JavaScript?

### `forEach()`

- Used to loop through an array and perform actions on each item.
- **Does not return** a new array.

```js
const numbers = [1, 2, 3, 4];
numbers.forEach((num) => {
console.log(num * 2); // Output: 2, 4, 6, 8
});
```

### `map()`

- Creates a **new array** by transforming each element.
- Does **not modify** the original array.

```js
const numbers = [1, 2, 3, 4];
const doubled = numbers.map((num) => num * 2);

console.log(doubled); // [2, 4, 6, 8]
console.log(numbers); // [1, 2, 3, 4]
```

### `filter()`

- Returns a **new array** with elements that pass the provided test.

```js
const numbers = [1, 2, 3, 4, 5, 6];
const even = numbers.filter((num) => num % 2 === 0);

console.log(even); // [2, 4, 6]
```

### `reduce()`

- Reduces an array to a **single value** using a function.
- Useful for totals, sums, or constructing objects.

```js
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, num) => acc + num, 0);

console.log(sum); // 15
```

### `find()`

- Returns the **first element** that matches the condition.
- Returns `undefined` if not found.

```js
const numbers = [1, 2, 3, 4, 5];
const found = numbers.find((num) => num > 3);

console.log(found); // 4
```

### `some()`

- Checks if **at least one** element satisfies the condition.
- Returns `true` or `false`.

```js
const nums = [1, 2, 3, 4];
console.log(nums.some((num) => num > 2)); // true
```

### `every()`

- Checks if **all** elements satisfy the condition.
- Returns `true` or `false`.

```js
const nums = [1, 2, 3, 4];
console.log(nums.every((num) => num > 0)); // true
```

### Array Methods & Behavior

| Method | Purpose | Returns New Array? | Modifies Original? | Notes |
| ----------- | -------------------------------- | ------------------ | -------------------- | -------------------------- |
| `forEach()` | Loop & perform action | ❌ No | ✅ Yes (if modified) | No return |
| `map()` | Transform each element | ✅ Yes | ❌ No | Shallow copy |
| `filter()` | Filter elements | ✅ Yes | ❌ No | Shallow copy |
| `reduce()` | Reduce array to a single value | ❌ No | ❌ No | Accumulator-based |
| `find()` | Find first match | ❌ No | ❌ No | Returns value or undefined |
| `some()` | At least one element passes test | ❌ No | ❌ No | Boolean |
| `every()` | All elements pass test | ❌ No | ❌ No | Boolean |

---

## ❓ What is the Difference Between `slice()` and `splice()` in JavaScript?

### ✂️ `slice()`

- Extracts a **portion** of an array.
- **Does not** modify the original array.
- Returns a **new array**.

```js
let numbers = [1, 2, 3, 4, 5];
let sliced = numbers.slice(1, 4);

console.log(sliced); // [2, 3, 4]
console.log(numbers); // [1, 2, 3, 4, 5]
```

### 🧨 `splice()`

- Used to **add/remove** items from an array.
- **Modifies** the original array.
- Returns an array of **removed elements**.

```js
let numbers = [1, 2, 3, 4, 5];
let removed = numbers.splice(1, 2); // start at index 1, remove 2 items

console.log(removed); // [2, 3]
console.log(numbers); // [1, 4, 5]
```

### `slice()` vs `splice()`

| Method | Returns New Array? | Modifies Original? | Use Case |
| ---------- | ------------------ | ------------------ | ------------------- |
| `slice()` | ✅ Yes | ❌ No | Extract portion |
| `splice()` | ✅ Yes (removed) | ✅ Yes | Add/remove elements |

---

## ❓ What is the Ternary Operator in JavaScript?

The **ternary operator** is a **shorthand version of the `if...else` statement** in JavaScript.
It allows you to write **conditional expressions** in a single line using three parts:

```js
condition ? expression_if_true : expression_if_false;
```

```js
let marks = 18;
let result = marks >= 40 ? "Pass" : "Fail";

console.log(result); // Output: "Fail"
```

### Explanation:

| Part | Description |
| ------------- | ---------------------------------- |
| `marks >= 40` | Condition to check |
| `'Pass'` | Executes if condition is **true** |
| `'Fail'` | Executes if condition is **false** |

### Why use the Ternary Operator?

- Cleaner and more readable than `if...else` for short conditions.
- Ideal for **inline decisions** like setting values or rendering content.

```js
let age = 20;
let status = age >= 18 ? "Adult" : "Minor";
console.log(status); // "Adult"

let isLoggedIn = false;
let message = isLoggedIn ? "Welcome back!" : "Please log in";
console.log(message); // "Please log in"
```

> Use ternary operators for **simple conditions only**.
>
> For complex logic, stick with `if...else` blocks for better readability.

---

## ❓ What is the Difference between Rest and Spread Operator in JavaScript?

Both **Rest** and **Spread** operators use the same syntax `...` but serve **different purposes** depending on context.

### Rest Operator (`...rest`)

- **Collects multiple elements** into a single array or object.
- Common in **function parameters** and **destructuring**.

#### 1. Rest in Function Parameters

```js
function print(...rest) {
return rest;
}
console.log(print(1, 2, 3)); // [1, 2, 3]
```

- All arguments passed to `print` are **gathered into an array**.

#### 2. Rest in Array Destructuring

```js
const [...rest] = [1, 2, 3];
console.log(rest); // [1, 2, 3]
```

- All elements collected into `rest`.

#### 3. Rest for Calculations

```js
function sum(...args) {
return args.reduce((a, b) => a + b);
}
console.log(sum(1, 2, 3, 4)); // 10
```

### Spread Operator (`...spread`)

- **Expands** arrays/objects into **individual elements**.
- Used in **combining, copying, and passing elements**.

#### 1. Spread to Combine Arrays

```js
const arr = [1, 2, 3];
const newArr = [...arr, 4, 5];
console.log(newArr); // [1, 2, 3, 4, 5]
```

#### 2. Spread to Merge Arrays

```js
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2];
console.log(combined); // [1, 2, 3, 4, 5, 6]
```

#### 3. Spread to Copy Array

```js
const original = [1, 2, 3];
const copy = [...original];
console.log(copy); // [1, 2, 3]
```

### Destructuring in JavaScript

Destructuring lets you **unpack values** from arrays or objects into **separate variables**.

#### Destructuring Arrays

```js
const arr = [1, 2, 3];
const [a, b, c] = arr;

console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
```

#### Array Destructuring with Rest

```js
const [first, second, ...rest] = [1, 2, 3, 4, 5];

console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]
```

#### Object Destructuring with Rest

```js
const user = { name: "Abdul Ahad", age: 30, role: "admin" };
const { name, ...details } = user;

console.log(name); // Abdul Ahad
console.log(details); // { age: 30, role: 'admin' }
```

| Feature | Rest Operator (`...rest`) | Spread Operator (`...spread`) |
| ----------------- | ----------------------------------- | --------------------------------------- |
| Purpose | Gathers items into one array/object | Spreads elements into individual values |
| Use Case | Function params, destructuring | Array copy, merge, pass as args |
| Syntax Position | On the **receiving** side | On the **sending** side |
| Return Value | Always returns array or object | Expands into individual values |
| Changes Original? | ❌ No | ❌ No |

### Rest Example (Function Arguments)

```js
function sum(...numbers) {
return numbers.reduce((acc, curr) => acc + curr, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 15
```

### Spread Example (Merge Arrays)

```js
let numbers = [1, 2, 3];
let newNumbers = [...numbers, 4, 5];
console.log(newNumbers); // [1, 2, 3, 4, 5]
```

---

## ❓ What are Different Data Types in JavaScript?

JavaScript has two main categories of data types:

### 1. Primitive Data Types

- Stored **by value** (directly in the **stack**)
- **Immutable** — cannot be changed once created
- Simple & fast

#### Types:

| Type | Example |
| ----------- | ---------------------- |
| `Number` | `let age = 25;` |
| `String` | `let name = "Ahad";` |
| `Boolean` | `let isOnline = true;` |
| `Null` | `let x = null;` |
| `Undefined` | `let y;` |
| `Symbol` | `let id = Symbol();` |
| `BigInt` | `let big = 123n;` |

> ✅ **Primitive values are compared by their actual value.**

### 2. Reference Data Types (Non-Primitives)

- Stored **by reference** (in the **heap**)
- **Mutable** — can be modified after creation
- Can store **multiple values**

#### Types:

| Type | Example |
| -------------------------- | ----------------------------------- |
| `Object` | `let user = { name: "Ahad" };` |
| `Array` | `let nums = [1, 2, 3];` |
| `Function` | `function greet() { return "Hi"; }` |
| `Date`, `Set`, `Map`, etc. | More complex structures |

> ❗ When you copy reference types, you're copying the **reference**, not the actual value.

| Feature | Primitive | Reference |
| ---------- | ------------------- | --------------- |
| Stored in | Stack | Heap |
| Copy Type | By Value | By Reference |
| Mutability | Immutable | Mutable |
| Comparison | Value-based (`===`) | Reference-based |

```js
// Primitive
let a = 5;
let b = a;
b = 10;
console.log(a); // 5 ✅ original unchanged

// Reference
let obj1 = { name: "Ahad" };
let obj2 = obj1;
obj2.name = "Ali";
console.log(obj1.name); // "Ali" ❗ changed because it's the same reference
```

- Use **primitive types** for simple, fixed values.
- Use **reference types** for collections, structured data, and behaviors.

---

## ❓ What is the Difference between `==` and `===`

Both `==` and `===` are used for **comparison**, but they behave differently.

### `==` (Loose Equality)

- Performs **type coercion**
- Converts operands to the same type before comparing

```js
5 == "5"; // true
true == 1; // true
null == undefined; // true
```

> ⚠️ Can cause **unexpected results** due to automatic type conversion.

### `===` (Strict Equality)

- **No type coercion**
- Compares both **value and type**

```js
5 === "5"; // false
true === 1; // false
null === undefined; // false
```

> More **predictable** and recommended in most cases.

### Bonus: Operator Behavior Examples

```js
console.log(1 + 2 + 3); // 6
console.log("1" + "2" + "3"); // "123"
console.log(1 + 2 + "3"); // "33"
console.log(1 + "2" + "2"); // "122"
console.log(1 + 2 + "3" + 4 + 5); // "3345"

console.log(false - 1); // -1
console.log(true + 1); // 2

console.log([1] + "abc"); // "1abc"
console.log(1 + "2" + +"2"); // "122"
console.log(1 + +"2" + "2"); // "32"
console.log(1 + -"1" + "2"); // "02"
console.log(1 + "1" + -"2"); // "11-2"

console.log("A" - "B" + "2"); // "NaN2"
console.log("A" - "B" + 2); // NaN
```

---

## ❓ What is Referential Equality?

Referential equality checks if **two variables refer to the same object in memory**.

- Primitives (`string`, `number`, `boolean`, etc.) are compared **by value**.
- Objects (`{}`, `[]`, `function`) are compared **by reference**.

```js
let a = { name: "Ahad" };
let b = a;
console.log(a === b); // ✅ true (same reference)

let c = { name: "Ahad" };
console.log(a === c); // ❌ false (different object, same content)
```

---

## ❓ What is the Difference between `null` and `undefined`

Both `null` and `undefined` represent "empty" or "missing" values, but they are **not the same**.

### `undefined`

- A variable is **declared** but **not assigned** a value.
- Automatically assigned by JavaScript if no value is set.

```js
let a;
console.log(a); // undefined
```

### `null`

- Manually assigned to indicate "no value" or "intentionally empty".
- Used when you want to clear a value on purpose.

```js
let b = null;
console.log(b); // null
```

### Comparison

```js
let a;
let b = null;

console.log(a === b); // false - different types
console.log(a == b); // true - loosely equal
```

- === compares both value and type
- == performs type coercion, so null and undefined are treated as equal

> Use null when you want to intentionally reset a variable.
> Be cautious with == — it can produce unexpected results due to type coercion.

---

## ❓ What is NaN?

**NaN** stands for **"Not-a-Number"**.

It is a special value in JavaScript used to represent **an invalid number** — the result of an operation that **fails to return a meaningful numeric value**.

```javascript
console.log(0 / 0); // NaN (undefined division)
console.log("abc" - 10); // NaN (invalid subtraction)
console.log(Math.sqrt(-1)); // NaN (imaginary number)
console.log(parseInt("xyz")); // NaN
```

- `NaN` is a number type:

```js
console.log(typeof NaN); // Output: "number"
```

- It does not equal itself:

```js
console.log(NaN === NaN); // false
console.log(Object.is(NaN, NaN)); // true (safe comparison)
```

- To check for `NaN`, use:

```js
console.log(Number.isNaN(NaN)); // true ✅
console.log(Number.isNaN("hello")); // false ✅
console.log(isNaN("hello")); // true ❌ (bad: coerces string to NaN first)
```

### Best Way to Check for NaN

```js
Number.isNaN(value); // Strict and safe
```

```js
console.log(Number.isNaN("abc")); // false (it's a string, not NaN)
console.log(Number.isNaN(NaN)); // true
```

### Real World Use Case

```js
function divide(a, b) {
if (b === 0) {
return NaN; // Division by zero
}
return a / b;
}

console.log(divide(10, 2)); // 5
console.log(divide(10, 0)); // NaN
```

## ❓ What is Strict Mode in JavaScript?

**Strict Mode** is a feature in JavaScript that helps you **write cleaner, more secure, and less error-prone code** by enabling **stricter parsing and error handling**.

You activate it by adding:

```js
"use strict";
```

It can be applied:

- At the top of a JS file
- Inside a specific function block

### Why Use Strict Mode?

It helps catch:

- Silent errors
- Accidental global variables
- Invalid assignments
- Deprecated or unsafe syntax

> Especially useful in large **codebases, teams**, or when using **classes/modules** (which are strict by default).

### Enabling Strict Mode

1. File-level

```js
"use strict";
x = 10; // ❌ Error: x is not defined
```

2. Function-level

```js
function doSomething() {
"use strict";
y = 5; // ❌ Error: y is not defined
}
```

> 💡 Note: ES6 class syntax always runs in strict mode automatically.

### Common Errors Caught by Strict Mode

| 🔍 Mistake | ❌ Without Strict | ✅ With Strict |
| ---------------------------------------------- | ------------------ | --------------- |
| Using undeclared variables | Allowed silently | ❌ Throws error |
| Assigning to read-only/global | No warning | ❌ Throw