🚀 Modern JavaScript ES6-ES2023

React ke liye essential JavaScript concepts - Interactive Learning Guide

1. var vs let vs const

Pehle JavaScript mein sirf var tha, lekin ES6 mein let aur const aaye jo better scope aur control dete hain.

Feature var let const
Scope Function-scoped Block-scoped Block-scoped
Reassignment ✅ Allowed ✅ Allowed ❌ Not Allowed
Hoisting ✅ Yes (undefined) ⚠️ Yes (TDZ) ⚠️ Yes (TDZ)
Redeclaration ✅ Allowed ❌ Not Allowed ❌ Not Allowed

🎮 Interactive Demo - Scope Testing

Click buttons to see scope differences
// var - function scoped if (true) { var x = "accessible"; } console.log(x); // "accessible" - var scope leak! // let - block scoped if (true) { let y = "blocked"; } // console.log(y); // Error! y is not defined // const - cannot reassign const z = "fixed"; // z = "new"; // Error! Cannot reassign const

2. Arrow Functions & Implicit Return

Arrow functions ek concise tarika hai functions likhne ka. Ye this binding ko parent se inherit karte hain, jo React mein bahut useful hai.

// Traditional function function add(a, b) { return a + b; } // Arrow function with explicit return const add = (a, b) => { return a + b; }; // Arrow function with implicit return const add = (a, b) => a + b; // Single parameter - no parentheses needed const square = x => x * x; // Implicit return of object (wrap in parentheses) const makePerson = name => ({ name, age: 25 });

🎮 Arrow Function Calculator

Results will appear here

3. Template Literals

Template literals backticks (`) use karte hain aur string interpolation ko easy banate hain. Multi-line strings aur expressions embed kar sakte hain directly.

// Old way - string concatenation const name = "Rahul"; const age = 25; const msg = "Hello " + name + ", you are " + age + " years old"; // Modern way - template literals const msg = `Hello ${name}, you are ${age} years old`; // Multi-line strings const html = ` <div> <h1>${name}</h1> <p>Age: ${age}</p> </div> `; // Expressions inside template literals const result = `Sum: ${10 + 20}, Product: ${5 * 4}`;

🎮 Template Literal Builder

Enter details and click button

4. Destructuring Objects & Arrays

Destructuring se hum objects aur arrays se values ko easily extract kar sakte hain. React props mein bahut use hota hai.

// Object Destructuring const user = { name: "Priya", age: 28, city: "Mumbai" }; const { name, age, city } = user; // Renaming variables const { name: userName, age: userAge } = user; // Default values const { name, country = "India" } = user; // Array Destructuring const colors = ["red", "green", "blue"]; const [first, second, third] = colors; // Skip elements const [, , third] = colors; // Rest operator in destructuring const [first, ...rest] = colors;

🎮 Destructuring Demo

Click buttons to see destructuring in action

5. Spread & Rest Operators (...)

Dono operators same symbol use karte hain (...) lekin context ke according different kaam karte hain. Spread expands, Rest collects.

// SPREAD - expands array/object const arr1 = [1, 2, 3]; const arr2 = [4, 5, 6]; const combined = [...arr1, ...arr2]; // [1,2,3,4,5,6] // Spread in objects (React state updates) const user = { name: "Amit", age: 30 }; const updatedUser = { ...user, age: 31 }; // REST - collects remaining elements function sum(...numbers) { return numbers.reduce((a, b) => a + b, 0); } sum(1, 2, 3, 4, 5); // 15 // Rest in destructuring const { name, ...otherProps } = user;

🎮 Spread & Rest Visualizer

Click buttons to see spread & rest operations

6. Array Methods (map, filter, reduce, find, some, every)

Ye methods React mein data manipulation ke liye bahut important hain. Immutable operations perform karte hain - original array change nahi hota.

const numbers = [1, 2, 3, 4, 5]; // map - transforms each element const doubled = numbers.map(n => n * 2); // [2,4,6,8,10] // filter - returns elements that pass test const evens = numbers.filter(n => n % 2 === 0); // [2,4] // reduce - reduces array to single value const sum = numbers.reduce((acc, n) => acc + n, 0); // 15 // find - returns first element that matches const found = numbers.find(n => n > 3); // 4 // some - checks if ANY element passes test const hasEven = numbers.some(n => n % 2 === 0); // true // every - checks if ALL elements pass test const allPositive = numbers.every(n => n > 0); // true

🎮 Array Methods Playground

Array: [2, 4, 6, 8, 10, 15, 20, 25, 30]

Click buttons to see array methods in action

7. Promises + Async/Await + Error Handling

Promises asynchronous operations handle karne ke liye use hote hain. async/await promises ko synchronous jaisa dikhata hai, making code cleaner.

// Promise basics const promise = new Promise((resolve, reject) => { if (success) { resolve("Data loaded!"); } else { reject("Error occurred"); } }); // Using .then().catch() promise .then(data => console.log(data)) .catch(err => console.error(err)); // Async/Await - cleaner syntax async function fetchData() { try { const response = await fetch('api/data'); const data = await response.json(); return data; } catch (error) { console.error('Error:', error); } }

🎮 Async Operations Simulator

Click buttons to see async operations

8. Deep Copy vs Shallow Copy

Shallow copy sirf top-level copy karta hai, nested objects reference share karte hain. Deep copy complete independent copy banata hai.

// Shallow Copy - spread operator const obj1 = { a: 1, b: { c: 2 } }; const shallow = { ...obj1 }; shallow.b.c = 99; // obj1.b.c is also 99! ⚠️ // Deep Copy - JSON method (simple objects only) const deep = JSON.parse(JSON.stringify(obj1)); deep.b.c = 99; // obj1.b.c remains 2 ✅ // Deep Copy - structuredClone (modern way) const deep2 = structuredClone(obj1);

🎮 Copy Behavior Visualizer

Click buttons to see copy differences

9. Optional Chaining (?.) & Nullish Coalescing (??)

Ye modern operators safely nested properties access karne aur default values set karne mein help karte hain.

// Optional Chaining - safely access nested properties const user = { name: "Raj", address: { city: "Delhi" } }; // Old way - multiple checks const city = user && user.address && user.address.city; // Modern way - optional chaining const city = user?.address?.city; // "Delhi" const zip = user?.address?.zip; // undefined (no error!) // Nullish Coalescing - default values const port = process.env.PORT ?? 3000; // 3000 if null/undefined // Difference from || operator const a = 0 || 10; // 10 (0 is falsy) const b = 0 ?? 10; // 0 (only null/undefined trigger ??)

🎮 Optional Chaining Demo

Click buttons to see operators in action

10. Debouncing & Throttling

Debouncing function ko tab call karta hai jab user typing/action stop kare. Throttling function ko fixed intervals pe call karta hai. Search bars aur scroll events mein use hota hai.

// DEBOUNCING - waits until user stops typing function debounce(func, delay) { let timeoutId; return function(...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; } // Usage in search const searchAPI = debounce((query) => { console.log(`Searching for: ${query}`); }, 500); // THROTTLING - limits execution rate function throttle(func, limit) { let inThrottle; return function(...args) { if (!inThrottle) { func.apply(this, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; }

🎮 Live Debouncing & Throttling

Debouncing (Search): Type karo aur 500ms baad function call hoga

Debounce calls: 0

Throttling (Button Click): Kitna bhi click karo, har 1 second mein ek hi call

Throttle calls: 0

11. Classes and OOP Essentials

Classes ES6 mein aaye, React class components mein use hote the. Now mostly functional components with hooks, lekin OOP concepts samajhna important hai.

// Class definition class Person { constructor(name, age) { this.name = name; this.age = age; } // Method greet() { return `Hello, I'm ${this.name}`; } // Static method static species() { return "Homo Sapiens"; } } // Inheritance class Student extends Person { constructor(name, age, grade) { super(name, age); // Call parent constructor this.grade = grade; } study() { return `${this.name} is studying`; } } const student = new Student("Priya", 20, "A");

🎮 Class Creation Demo

Create a student to see class methods in action

12. Modules (import/export)

ES6 Modules code ko organize karne ka modern tarika hai. React components, utilities, aur constants ko alag files mein rakhte hain.

// mathUtils.js - Named exports export const add = (a, b) => a + b; export const subtract = (a, b) => a - b; export const PI = 3.14159; // Default export const multiply = (a, b) => a * b; export default multiply; // Importing - Named imports import { add, subtract, PI } from './mathUtils'; // Importing default export import multiply from './mathUtils'; // Import everything import * as math from './mathUtils'; // Rename imports import { add as sum } from './mathUtils';

React mein usage:

// Component.jsx import React, { useState, useEffect } from 'react'; import Button from './Button'; import { formatDate } from './utils'; export default function MyComponent() { // Component code }

13. Default Parameters

Default parameters se function arguments ko default values de sakte hain agar value pass nahi ki.

// Old way function greet(name) { name = name || "Guest"; return `Hello ${name}`; } // Modern way - default parameters function greet(name = "Guest") { return `Hello ${name}`; } // Multiple defaults function createUser(name = "Anonymous", role = "user", active = true) { return { name, role, active }; } // Default can be expressions function calculate(a, b = a * 2) { return a + b; }

🎮 Default Parameters Demo

Click buttons to test default parameters

🎯 Interview Questions

Easy

Q1: What is the difference between let, const, and var?

var:

  • Function-scoped (not block-scoped)
  • Can be redeclared and reassigned
  • Hoisted with undefined value
  • Creates property on global object when declared globally

let:

  • Block-scoped { }
  • Cannot be redeclared, but can be reassigned
  • Temporal Dead Zone (TDZ) - cannot access before declaration
  • Best for variables that will change

const:

  • Block-scoped { }
  • Cannot be redeclared or reassigned
  • Must be initialized at declaration
  • Object/Array properties can still be modified (reference is constant, not content)
Easy

Q2: Explain arrow functions and when to use them in React.

Arrow Functions: Concise syntax for writing functions with lexical 'this' binding.

Key differences from regular functions:

  • No own 'this' - inherits from parent scope
  • Cannot be used as constructors
  • No 'arguments' object
  • Implicit return for single expressions

Use in React:

  • Event handlers: onClick={() => handleClick()}
  • Array methods: data.map(item => <Component />)
  • Functional components
  • Callbacks in useEffect, useState
Medium

Q3: What is the difference between map(), filter(), and reduce()? Give React examples.

map(): Transforms each element and returns new array of same length

// React: Rendering list
users.map(user => <UserCard key={user.id} user={user} />)

filter(): Returns new array with elements that pass a test

// React: Filtering active users
activeUsers = users.filter(user => user.active)

reduce(): Reduces array to single value (sum, object, etc.)

// React: Calculate total price
const total = cart.reduce((sum, item) => sum + item.price, 0)

Can be chained:

products
  .filter(p => p.inStock)
  .map(p => p.price)
  .reduce((sum, price) => sum + price, 0)
Medium

Q4: Explain Promises, async/await, and error handling in API calls.

Promises: Objects representing eventual completion/failure of async operation

Three states: Pending → Fulfilled/Rejected

Promise approach:

fetch('/api/users')
  .then(res => res.json())
  .then(data => console.log(data))
  .catch(err => console.error(err))
  .finally(() => setLoading(false))

Async/Await approach (cleaner):

async function fetchUsers() {
  try {
    const res = await fetch('/api/users');
    const data = await res.json();
    setUsers(data);
  } catch (error) {
    setError(error.message);
  } finally {
    setLoading(false);
  }
}

Key points:

  • async functions always return a Promise
  • await pauses execution until Promise resolves
  • Always use try-catch for error handling
  • finally block runs regardless of success/failure
Medium

Q5: What is the difference between shallow copy and deep copy? How do you create them?

Shallow Copy: Copies top-level properties only. Nested objects/arrays are still referenced.

// Spread operator (shallow)
const copy = { ...original };
const arrCopy = [...originalArr];

// Object.assign (shallow)
const copy = Object.assign({}, original);

Deep Copy: Creates completely independent copy with all nested levels.

// JSON method (limitations: no functions, dates, undefined)
const deepCopy = JSON.parse(JSON.stringify(original));

// structuredClone (modern, best)
const deepCopy = structuredClone(original);

// Lodash library
const deepCopy = _.cloneDeep(original);

React State Management:

  • Never mutate state directly
  • Use spread for shallow updates: setState({...state, name: 'New'})
  • For nested updates, create new objects at each level
Hard

Q6: Explain debouncing vs throttling with real-world React use cases.

Debouncing: Delays function execution until after a specified time has passed since the last call.

Use cases: Search bars, auto-save, window resize

// Search implementation
const searchAPI = debounce((query) => {
  fetch(`/api/search?q=${query}`)
    .then(res => res.json())
    .then(setResults);
}, 500);

// In component
<input onChange={(e) => searchAPI(e.target.value)} />

Throttling: Ensures function executes at most once in a specified time period.

Use cases: Scroll events, button clicks, window resize with live updates

// Infinite scroll
const handleScroll = throttle(() => {
  if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
    loadMoreData();
  }
}, 1000);

window.addEventListener('scroll', handleScroll);

Key Difference:

  • Debounce: Wait until user stops (delay after last event)
  • Throttle: Execute at regular intervals (ignore intermediate events)
Hard

Q7: Explain optional chaining (?.) and nullish coalescing (??). Why are they better than older alternatives?

Optional Chaining (?.): Safely access nested properties without checking each level

// Old way - verbose
const city = user && user.address && user.address.city;

// New way - concise
const city = user?.address?.city;

// Works with methods
user?.getName?.();

// Works with arrays
users?.[0]?.name;

Nullish Coalescing (??): Returns right operand only when left is null/undefined

// || problem: treats 0, '', false as falsy
const count = 0;
const value1 = count || 10;  // 10 (wrong!)
const value2 = count ?? 10;  // 0 (correct!)

// React example
function Component({ timeout = 0 }) {
  // timeout can be 0 (valid), but || would fail
  const delay = timeout ?? 1000;
}

Why better:

  • Shorter, more readable code
  • No runtime errors for undefined access
  • ?? only checks null/undefined, not all falsy values
  • Prevents bugs with 0, '', false values