πŸ“– JavaScript β€” Complete Notes

Beginner to Intermediate Β· By Codeware IT Pvt. Ltd., Dehradun

βœ” Beginner Friendly βœ” Interview Ready βœ” Practice Exercises βœ” Real Examples

πŸš€ What is JavaScript?

The language that makes web pages alive

Imagine a website as a house. HTML is the walls and structure, CSS is the paint and decoration, and JavaScript is the electricity β€” it makes everything work: lights switch on, doors open, appliances run.

JavaScript is a programming language that runs inside your browser. It lets you build interactive buttons, validate forms, fetch data from servers, and build entire apps like Google Maps or Gmail.

πŸ“Œ Quick Facts

  • Created by Brendan Eich in 1995 (in just 10 days!)
  • Originally called Mocha, then LiveScript, then JavaScript
  • Runs on every modern browser β€” no installation needed
  • Used on 98% of websites globally
  • Now also runs on servers via Node.js

πŸ”€ JS Syntax Basics

Syntax means the rules for writing code β€” like grammar rules in English. JavaScript has simple rules:

// This is a comment β€” it is not run by the browser
console.log("Hello, World!"); // Prints output to the console

// Semicolons end statements (optional but good practice)
let name = "Riya";            // Variable declaration
let age  = 22;                // Number
let isStudent = true;         // Boolean (true/false)

// Calling a function
alert("Welcome to JavaScript!");

πŸ“Ž How to Add JavaScript to HTML

There are 3 ways to add JS to your HTML page:

MethodWhere?Best For
InlineInside an HTML tagTiny one-liners (avoid for big projects)
Internal<script> tag in HTML fileSmall pages
ExternalSeparate .js fileβœ… Recommended for all real projects
/* ── External JS (best practice) ──
   In your HTML: <script src="app.js" defer></script>
   Inside app.js: */

console.log("External JS is loaded!");

// The 'defer' attribute means the script runs AFTER
// the HTML is fully loaded β€” preventing errors.

πŸ’¬ JS Comments

// Single-line comment β€” great for short notes

/*
  Multi-line comment
  Use this for longer explanations
  or to "comment out" blocks of code during debugging
*/

console.log("Comments are ignored by the browser");

πŸ“€ JS Output Methods

// 1. Show in browser console (Developer Tools)
console.log("Best for debugging!");

// 2. Show a popup alert box
alert("Hello from JavaScript!");

// 3. Write directly into the HTML page
document.write("<h2>Hello World</h2>");

// 4. Change an element's text
document.getElementById("output").innerText = "Updated!";

// 5. console.error / console.warn
console.error("Something went wrong");
console.warn("Be careful here");

🎯 JS Events

An event is something that happens on the page β€” a click, a keypress, a hover. JavaScript can listen for these and respond.

// Method 1: Inline (HTML attribute)
// <button onclick="sayHello()">Click Me</button>

function sayHello() {
  alert("You clicked the button!");
}

// Method 2: addEventListener (recommended)
const btn = document.getElementById("myBtn");

btn.addEventListener("click", function() {
  console.log("Button was clicked!");
});

// Common Events:
// click, dblclick, mouseover, mouseout
// keydown, keyup, keypress
// submit, change, focus, blur
// load, resize, scroll

βœ… Section Summary

  • JavaScript makes websites interactive
  • Always link your JS with <script src="app.js" defer></script>
  • Use console.log() to debug your code
  • Events let users interact with the page

πŸ“¦ JavaScript Variables & Data Types

Where your data lives

A variable is like a labelled box πŸ“¦. You put a value inside it and use the label to find it later.

var, let, const β€” What's the Difference?

KeywordScopeRe-declare?Re-assign?Hoisted?
varFunctionβœ… Yesβœ… Yesβœ… Yes (as undefined)
letBlock❌ Noβœ… Yes⚠️ TDZ
constBlock❌ No❌ No⚠️ TDZ
// ── var (old way β€” avoid in modern code) ──
var city = "Dehradun";
var city = "Delhi"; // OK with var (can redeclare) β€” confusing!

// ── let (modern, use this for changing values) ──
let score = 0;
score = 50;          // βœ… can change
// let score = 100;  // ❌ cannot redeclare

// ── const (modern, use for values that won't change) ──
const PI = 3.14159;
// PI = 3;           // ❌ TypeError: Assignment to constant variable

// Example: student record
const studentName = "Aarav";
let studentMarks  = 85;

studentMarks = 90;  // marks can change
// studentName = "Rahul"; // name stays same (const)

console.log(studentName, studentMarks);

πŸ“Š JavaScript Data Types

TypeExampletypeof result
String"Hello""string"
Number42, 3.14"number"
Booleantrue, false"boolean"
Undefinedlet x;"undefined"
Nullnull"object" ⚠️
Object{name:"Ram"}"object"
Array[1,2,3]"object"
SymbolSymbol("id")"symbol"
BigInt9999n"bigint"

πŸ”„ Type Conversion vs Type Coercion

// ── TYPE CONVERSION (manual, explicit) ──
let numStr = "42";
let num    = Number(numStr);   // β†’ 42
let str    = String(100);       // β†’ "100"
let bool   = Boolean(0);        // β†’ false

// ── TYPE COERCION (automatic, implicit β€” can be tricky!) ──
console.log("5" + 2);    // β†’ "52"  (number becomes string)
console.log("5" - 2);    // β†’ 3     (string becomes number)
console.log(true + 1);   // β†’ 2
console.log(false + "x");// β†’ "falsex"

// Best practice: always convert explicitly to avoid confusion
let input = "10";
let total = Number(input) + 5; // β†’ 15 βœ…

πŸ—οΈ Hoisting

Hoisting means JavaScript moves declarations to the top of their scope before running the code. Imagine your teacher knowing your name before class starts because the register was prepared in advance.

// var is hoisted as undefined
console.log(color); // β†’ undefined (no error!)
var color = "blue";

// let/const are hoisted but NOT initialized (TDZ = Temporal Dead Zone)
// console.log(animal); // ❌ ReferenceError
let animal = "dog";

// Functions are fully hoisted
greet(); // βœ… Works!
function greet() {
  console.log("Hello from hoisted function!");
}

⚠️ Common Mistake

Beginners often use var everywhere. Always prefer const by default; use let if you need to reassign. Never use var in modern code.

Interview Questions
Q1. What is the difference between == and ===? β–Ό
== compares values after type coercion ("5" == 5 is true). === compares value AND type without coercion ("5" === 5 is false). Always use === to avoid bugs.
Q2. What is the Temporal Dead Zone (TDZ)? β–Ό
The TDZ is the time between when a let or const variable is hoisted and when it is initialized. Accessing it during this period throws a ReferenceError.

πŸ’ͺ Practice Exercise

  1. Create variables for your name, age, city, and whether you are a student. Use the correct keyword (const/let) for each.
  2. Try adding a string and a number. What do you get? Why?
  3. Check the type of null using typeof. Are you surprised?

βœ… Section Summary

  • Use const by default, let to reassign, avoid var
  • JavaScript has 8 data types; typeof null is "object" (historical bug)
  • Coercion is automatic; conversion is manual
  • Hoisting moves declarations to top; let/const have TDZ

βš™οΈ JavaScript Operators

Tools that perform operations on values

βž• Arithmetic Operators

let a = 10, b = 3;

console.log(a + b);  // 13  β€” Addition
console.log(a - b);  // 7   β€” Subtraction
console.log(a * b);  // 30  β€” Multiplication
console.log(a / b);  // 3.33 β€” Division
console.log(a % b);  // 1   β€” Modulus (remainder)
console.log(a ** b); // 1000 β€” Exponentiation (10Β³)
console.log(++a);    // 11  β€” Pre-increment
console.log(b--);    // 3   β€” Post-decrement (returns then decrements)

πŸ“‹ Assignment Operators

let x = 10;
x += 5;   // x = x + 5  β†’ 15
x -= 3;   // x = x - 3  β†’ 12
x *= 2;   // x = x * 2  β†’ 24
x /= 4;   // x = x / 4  β†’ 6
x %= 4;   // x = x % 4  β†’ 2
x **= 3;  // x = x ** 3 β†’ 8
x ??= 100;// x = x ?? 100 β€” assign only if x is null/undefined

πŸ” Comparison Operators

console.log(5 == "5");   // true  (loose β€” coerces type)
console.log(5 === "5");  // false (strict β€” checks type too) βœ… prefer this
console.log(5 != "5");   // false
console.log(5 !== "5");  // true  βœ… prefer this
console.log(10 > 5);     // true
console.log(10 < 5);     // false
console.log(10 >= 10);   // true
console.log(10 <= 9);    // false

🧠 Logical Operators

// && (AND) β€” both must be true
console.log(true && true);   // true
console.log(true && false);  // false

// || (OR) β€” at least one must be true
console.log(false || true);  // true
console.log(false || false); // false

// ! (NOT) β€” reverses
console.log(!true);  // false

// Nullish Coalescing (??) β€” use right side if left is null/undefined
let user = null;
let name = user ?? "Guest";  // "Guest"

// Optional Chaining (?.) β€” safe property access
let profile = null;
console.log(profile?.name);  // undefined (no error!)

πŸ”€ Ternary Operator

The ternary operator is a short if-else. Think of it as: "Is it true? Do this : otherwise do that"

// Syntax: condition ? valueIfTrue : valueIfFalse

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

// Real-life: show discount or not
let isMember = true;
let price = isMember ? "β‚Ή499 (10% OFF)" : "β‚Ή549";
console.log(price);

// Nested ternary (use carefully!)
let score = 75;
let grade = score >= 90 ? "A" : score >= 70 ? "B" : "C";
console.log(grade); // "B"

typeof Operator

console.log(typeof "Hello");       // "string"
console.log(typeof 42);            // "number"
console.log(typeof true);          // "boolean"
console.log(typeof undefined);     // "undefined"
console.log(typeof null);          // "object" ← famous JS bug
console.log(typeof {});            // "object"
console.log(typeof []);            // "object"
console.log(typeof function(){}); // "function"

βœ… Section Summary

  • Always prefer === over == for comparisons
  • ?? is great for default values when something might be null
  • Ternary is a one-line if-else β€” don't nest too deep
  • typeof null === "object" is a known bug, not a feature

πŸ”€ Conditional Flow

Make decisions in your code

// ── if / else if / else ──
let marks = 78;

if (marks >= 90) {
  console.log("Grade: A");
} else if (marks >= 75) {
  console.log("Grade: B");     // ← this runs
} else if (marks >= 60) {
  console.log("Grade: C");
} else {
  console.log("Grade: Fail");
}

// ── Switch Case (multiple fixed values) ──
let day = "Monday";

switch(day) {
  case "Monday":
    console.log("Start of the work week!");
    break;
  case "Friday":
    console.log("Almost weekend!");
    break;
  case "Saturday":
  case "Sunday":
    console.log("It's the weekend! πŸŽ‰");
    break;
  default:
    console.log("Just another weekday");
}

// ── Short-circuit evaluation (cool trick!) ──
let isLoggedIn = true;
isLoggedIn && console.log("Welcome back!"); // prints if true

let username = null;
let displayName = username || "Anonymous";  // fallback
console.log(displayName); // "Anonymous"

πŸ’‘ When to use what?

  • Use if/else for range checks (marks > 50, age < 18)
  • Use switch for exact value matching (day names, menu options)
  • Use ternary for simple one-line decisions

πŸ” JavaScript Loops

Repeat tasks without writing the same code again and again

Imagine you have to print numbers 1 to 100. Writing console.log(1) 100 times would be crazy! Loops do this in 3 lines.

for loop

// Syntax: for(start; condition; step)
for (let i = 1; i <= 5; i++) {
  console.log("Count:", i);
}
// 1, 2, 3, 4, 5

// Loop through array
let fruits = ["🍎 Apple", "🍌 Banana", "🍊 Orange"];
for (let i = 0; i < fruits.length; i++) {
  console.log(fruits[i]);
}

while loop

// Runs AS LONG AS condition is true
let count = 0;
while (count < 3) {
  console.log("count is", count);
  count++;
}
// 0, 1, 2

// Real-life: keep asking until correct answer
let answer;
let correctAnswer = "Dehradun";
// (In browser you'd use prompt())
// while(answer !== correctAnswer) { answer = prompt("Capital of Uttarakhand?"); }

do…while loop

// Runs AT LEAST ONCE β€” checks condition AFTER first run
let num = 10;
do {
  console.log("num:", num);  // prints 10 even though condition fails
  num++;
} while (num < 5);
// Output: num: 10  (runs once)

for…of (for arrays/strings)

let colors = ["red", "green", "blue"];
for (let color of colors) {
  console.log(color);  // red, green, blue
}

// Works on strings too!
for (let char of "JS") {
  console.log(char);   // J, S
}

for…in (for objects)

let student = { name: "Aarav", age: 20, city: "Dehradun" };

for (let key in student) {
  console.log(key, ":", student[key]);
}
// name : Aarav
// age  : 20
// city : Dehradun

break and continue

// break β€” exit the loop entirely
for (let i = 0; i < 10; i++) {
  if (i === 5) break;
  console.log(i);  // 0, 1, 2, 3, 4
}

// continue β€” skip this iteration and go to next
for (let i = 0; i < 6; i++) {
  if (i === 3) continue;
  console.log(i);  // 0, 1, 2, 4, 5 (3 is skipped)
}

⚠️ Common Mistake: Infinite Loop

If you forget to increment your counter (i++), the loop runs forever and crashes your browser tab! Always double-check your loop condition.

βœ… Section Summary

  • for β€” when you know how many times to loop
  • while β€” when condition-based, count unknown
  • do-while β€” when it must run at least once
  • for-of β€” for arrays/strings (values)
  • for-in β€” for object keys
  • break stops, continue skips

🎯 JavaScript Functions

Reusable blocks of code β€” write once, use many times

A function is like a recipe. You write the recipe once, and anytime you want that dish, you just "call" it.

Different Ways to Write Functions

// 1. Function Declaration (hoisted β€” can call before definition)
function greet(name) {
  return "Hello, " + name + "!";
}
console.log(greet("Aarav")); // "Hello, Aarav!"

// 2. Function Expression (not hoisted)
const add = function(a, b) {
  return a + b;
};
console.log(add(3, 4));  // 7

// 3. Arrow Function (shorter syntax, no own 'this')
const multiply = (a, b) => a * b;
console.log(multiply(5, 6)); // 30

// 4. IIFE β€” Immediately Invoked Function Expression
(function() {
  console.log("I run immediately!");
})();

// 5. Named Arrow (stored in variable)
const square = n => n * n;
console.log(square(9)); // 81

Default Parameters & Rest Parameters

// Default parameters
function welcome(name = "Guest", city = "Dehradun") {
  return `Welcome ${name} from ${city}!`;
}
console.log(welcome());              // Welcome Guest from Dehradun!
console.log(welcome("Priya", "Mumbai")); // Welcome Priya from Mumbai!

// Rest parameters β€” collect extra arguments into an array
function sum(...numbers) {
  return numbers.reduce((total, n) => total + n, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 15

Recursion

Recursion = a function calling itself. Like looking in a mirror that reflects another mirror. Perfect for problems that repeat in smaller versions.

// Factorial: 5! = 5 Γ— 4 Γ— 3 Γ— 2 Γ— 1 = 120
function factorial(n) {
  if (n <= 1) return 1;         // base case β€” stops the recursion
  return n * factorial(n - 1);  // recursive call
}
console.log(factorial(5)); // 120
console.log(factorial(0)); // 1

Pass by Value vs Pass by Reference

// Primitives are PASS BY VALUE (copy is made)
function changeNum(n) { n = 100; }
let x = 5;
changeNum(x);
console.log(x); // Still 5 β€” original not changed

// Objects are PASS BY REFERENCE (same memory location)
function changeObj(obj) { obj.name = "Priya"; }
let person = { name: "Aarav" };
changeObj(person);
console.log(person.name); // "Priya" β€” original IS changed!
Interview Questions
Q1. What is a closure in JavaScript? β–Ό
A closure is when an inner function remembers variables from its outer function even after the outer function has finished running. Example: function counter() { let count = 0; return () => ++count; } β€” the returned arrow function "closes over" the count variable.
Q2. What is the difference between arrow functions and regular functions? β–Ό
Arrow functions: (1) have shorter syntax, (2) don't have their own this β€” they inherit it from the surrounding scope, (3) cannot be used as constructors, (4) don't have arguments object. Regular functions have all of these.

πŸ’ͺ Practice

  1. Write a function that takes a name and returns a greeting
  2. Write an arrow function to find the area of a rectangle
  3. Write a recursive function to calculate the nth Fibonacci number

πŸ“š JavaScript Arrays

Store many values in one place

An array is like a numbered shelf πŸ“š. Each spot (index) holds one item. Arrays start at index 0.

// Create an array
let fruits = ["Apple", "Banana", "Mango", "Orange"];

// Access elements (0-based index)
console.log(fruits[0]); // "Apple"
console.log(fruits[2]); // "Mango"
console.log(fruits[fruits.length - 1]); // Last item: "Orange"

// ── Essential Array Methods ──

// push / pop (end)
fruits.push("Grapes");    // Add to end β†’ ["Apple","Banana","Mango","Orange","Grapes"]
fruits.pop();             // Remove from end β†’ ["Apple","Banana","Mango","Orange"]

// unshift / shift (start)
fruits.unshift("Kiwi");   // Add to start
fruits.shift();           // Remove from start

// splice (remove or insert anywhere)
fruits.splice(1, 1);      // Remove 1 item at index 1
fruits.splice(1, 0, "Lychee"); // Insert at index 1

// slice (copy a portion β€” doesn't modify original)
let some = fruits.slice(1, 3); // Items at index 1 and 2

// indexOf / includes
console.log(fruits.indexOf("Mango")); // 2 or -1 if not found
console.log(fruits.includes("Apple")); // true or false

// join (array β†’ string)
console.log(fruits.join(", ")); // "Apple, Banana, Mango"

// reverse and sort
let nums = [3, 1, 4, 1, 5, 9];
nums.sort((a, b) => a - b); // [1, 1, 3, 4, 5, 9]
nums.reverse();              // [9, 5, 4, 3, 1, 1]

Higher-Order Array Methods

let numbers = [1, 2, 3, 4, 5, 6];

// map β€” transform each item, returns NEW array
let doubled = numbers.map(n => n * 2);
console.log(doubled); // [2, 4, 6, 8, 10, 12]

// filter β€” keep items that pass the test, returns NEW array
let evens = numbers.filter(n => n % 2 === 0);
console.log(evens); // [2, 4, 6]

// reduce β€” boil array down to single value
let total = numbers.reduce((acc, n) => acc + n, 0);
console.log(total); // 21

// forEach β€” loop through (doesn't return anything)
numbers.forEach(n => console.log(n));

// find β€” first item that passes test
let firstEven = numbers.find(n => n % 2 === 0); // 2

// every / some
console.log(numbers.every(n => n > 0));  // true (all positive)
console.log(numbers.some(n => n > 5));   // true (6 is > 5)

// flat β€” flatten nested arrays
let nested = [1, [2, 3], [4, [5]]];
console.log(nested.flat());    // [1, 2, 3, 4, [5]]
console.log(nested.flat(2));   // [1, 2, 3, 4, 5]

// Remove duplicates
let arr = [1, 2, 2, 3, 3, 4];
let unique = [...new Set(arr)]; // [1, 2, 3, 4]

🌟 Pro Tip: Chain array methods!

let result = [1,2,3,4,5,6]
  .filter(n => n % 2 === 0)   // [2, 4, 6]
  .map(n => n * 10)            // [20, 40, 60]
  .reduce((a, b) => a + b, 0); // 120
console.log(result); // 120

πŸ—‚οΈ JavaScript Objects

Key-value pairs β€” the heart of JavaScript

An object is like a person's profile card πŸͺͺ β€” it has properties (name, age, city) and can also have actions (methods).

// Object literal (most common way)
const student = {
  name: "Aarav Sharma",
  age: 21,
  city: "Dehradun",
  isEnrolled: true,
  // Method inside object
  greet() {
    return `Hi! I am ${this.name} from ${this.city}.`;
  }
};

// Access properties
console.log(student.name);       // dot notation
console.log(student["city"]);    // bracket notation (for dynamic keys)
console.log(student.greet());

// Add / Update / Delete
student.course = "JavaScript";  // add
student.age = 22;               // update
delete student.isEnrolled;      // delete

// Check if key exists
console.log("name" in student);  // true
console.log(student.hasOwnProperty("city")); // true

// Destructuring (extract values cleanly)
const { name, age, city = "Unknown" } = student;
console.log(name, age, city);

// Spread operator (copy / merge objects)
const extra = { course: "React", year: 2025 };
const merged = { ...student, ...extra };

// Object.keys / values / entries
console.log(Object.keys(student));    // ["name", "age", "city", ...]
console.log(Object.values(student));  // ["Aarav Sharma", 22, "Dehradun", ...]
console.log(Object.entries(student)); // [["name","Aarav Sharma"], ...]

// Freeze (prevent changes)
const config = Object.freeze({ API: "https://api.codewareit.in" });
// config.API = "other"; // silently ignored
Interview Q&A
Q1. What does this refer to inside an object method? β–Ό
Inside a regular function method, this refers to the object that called the method. In an arrow function inside an object, this refers to the outer scope, NOT the object itself β€” this is a common gotcha!

πŸ“ JavaScript Strings

Working with text in JavaScript

// Template literals (backtick) β€” the modern way
let name = "Codeware IT";
let city = "Dehradun";
console.log(`${name} is based in ${city}!`);
// Multi-line strings:
let html = `
  <div>
    <h1>${name}</h1>
  </div>
`;

// ── Key String Methods ──
let str = "  Hello, JavaScript!  ";

str.trim()          // "Hello, JavaScript!"  β€” remove whitespace
str.toUpperCase()   // "  HELLO, JAVASCRIPT!  "
str.toLowerCase()   // "  hello, javascript!  "
str.includes("Java")         // true
str.startsWith("Hello")      // false (leading spaces)
str.trim().startsWith("Hello") // true
str.indexOf("Java")          // 8
str.replace("JavaScript", "World") // "  Hello, World!  "
str.split(", ")              // ["  Hello", "JavaScript!  "]
str.slice(2, 7)              // "Hello"
str.padStart(25, "*")        // pads to length 25
str.repeat(2)                // repeats the string twice

// String to number and back
let numStr = "42.5";
console.log(Number(numStr));     // 42.5
console.log(parseInt(numStr));   // 42
console.log(parseFloat(numStr)); // 42.5
console.log((3.14159).toFixed(2)); // "3.14"

// camelCase converter
function toCamelCase(str) {
  return str.replace(/-./g, x => x[1].toUpperCase());
}
console.log(toCamelCase("my-best-course")); // "myBestCourse"

⏳ Promises & Async/Await

Handle tasks that take time β€” like fetching data from a server

Imagine ordering food at a restaurant πŸ•. You don't wait at the counter β€” you sit down and the waiter promises to bring your order. You continue talking; when food arrives, you eat (or if it's wrong, you complain). That's a Promise in JS!

Understanding Promises

// A Promise has 3 states:
// pending β†’ fulfilled (resolve) or rejected (reject)

const orderFood = new Promise((resolve, reject) => {
  let foodReady = true;  // pretend server check
  if (foodReady) {
    resolve("πŸ• Pizza is ready!");
  } else {
    reject("❌ Sorry, out of stock");
  }
});

orderFood
  .then(msg => console.log("Success:", msg))  // on resolve
  .catch(err => console.log("Error:", err))    // on reject
  .finally(() => console.log("Order processed")); // always runs

// Promise.all β€” wait for ALL to finish
const p1 = Promise.resolve("Data 1");
const p2 = Promise.resolve("Data 2");
const p3 = new Promise(res => setTimeout(() => res("Data 3"), 1000));

Promise.all([p1, p2, p3]).then(values => console.log(values));
// ["Data 1", "Data 2", "Data 3"] after 1 second

// Promise.race β€” first one wins
Promise.race([p1, p3]).then(v => console.log(v)); // "Data 1"

// Promise.any β€” first SUCCESS wins (ignores rejections)
// Promise.allSettled β€” waits for all, never rejects

Async/Await β€” Cleaner Promise Syntax

// async/await makes async code look synchronous (easier to read!)

async function fetchUser(id) {
  try {
    // Simulate API call (replace with real fetch)
    const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
    
    if (!response.ok) throw new Error("User not found!");
    
    const user = await response.json();
    console.log("User:", user.name);
    return user;
  } catch (error) {
    console.error("Something went wrong:", error.message);
  }
}

fetchUser(1);

// Parallel async calls (faster!)
async function getMultipleUsers() {
  const [user1, user2] = await Promise.all([
    fetch("https://jsonplaceholder.typicode.com/users/1").then(r => r.json()),
    fetch("https://jsonplaceholder.typicode.com/users/2").then(r => r.json()),
  ]);
  console.log(user1.name, user2.name);
}

Callbacks β†’ Promises β†’ Async/Await

StyleReadabilityError HandlingModern?
CallbacksGets messy (callback hell)ManualOld (avoid deep nesting)
PromisesChained .then().catch()Good
Async/AwaitReads like sync codetry/catchβœ… Best
Interview Q&A
Q1. What is the Event Loop? β–Ό
The event loop is JavaScript's way of handling async operations. JS is single-threaded, so it can only do one thing at a time. The Call Stack runs synchronous code. When async tasks (setTimeout, fetch) complete, their callbacks go to the Callback Queue. The Event Loop constantly checks β€” if the Call Stack is empty, it moves the next callback from the queue to the stack.
Q2. What is the difference between microtasks and macrotasks? β–Ό
Microtasks (Promises, queueMicrotask) run BEFORE the next macrotask (setTimeout, setInterval). This means Promise callbacks always run before setTimeout callbacks, even if setTimeout has 0ms delay.

πŸ“‹ JavaScript JSON

The universal language for data transfer

JSON (JavaScript Object Notation) is a text format for storing and sending data. Think of it as a universal packing format β€” like a box that any program can open.

// JS Object β†’ JSON string (for sending to server)
const student = {
  name: "Priya",
  age: 20,
  skills: ["HTML", "CSS", "JavaScript"],
  address: { city: "Dehradun", state: "Uttarakhand" }
};

const jsonString = JSON.stringify(student);
console.log(jsonString);
// '{"name":"Priya","age":20,"skills":["HTML","CSS","JavaScript"],...}'

// Pretty print (for reading / display)
const pretty = JSON.stringify(student, null, 2);
console.log(pretty);

// JSON string β†’ JS Object (for receiving from server)
const parsed = JSON.parse(jsonString);
console.log(parsed.name);          // "Priya"
console.log(parsed.skills[0]);     // "HTML"
console.log(parsed.address.city);  // "Dehradun"

// Check if a key exists
console.log("name" in parsed);  // true
console.log(parsed.hasOwnProperty("age")); // true

// Add element to JSON object
parsed.course = "React";
console.log(JSON.stringify(parsed));

⚠️ JSON Rules

  • Keys MUST be double-quoted strings
  • No functions, undefined, or symbols allowed
  • Use JSON.parse() safely inside try/catch (server data might be malformed)

🌐 Fetch API & HTTP Methods

Get and send data from/to servers

// ── GET request (fetching data) ──
async function getUsers() {
  try {
    const res  = await fetch("https://jsonplaceholder.typicode.com/users");
    const data = await res.json();
    data.forEach(user => console.log(user.name));
  } catch (err) {
    console.error("Fetch failed:", err);
  }
}
getUsers();

// ── POST request (sending data) ──
async function createPost(postData) {
  const res = await fetch("https://jsonplaceholder.typicode.com/posts", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(postData)
  });
  const created = await res.json();
  console.log("Created:", created);
}
createPost({ title: "My First Post", body: "Hello!", userId: 1 });

// ── PUT vs PATCH ──
// PUT replaces the ENTIRE resource
// PATCH updates only specified fields
async function updateUser(id, changes) {
  const res = await fetch(`https://api.example.com/users/${id}`, {
    method: "PATCH",        // only update what changed
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(changes)
  });
  return res.json();
}
MethodActionBody?
GETRead data❌ No
POSTCreate new dataβœ… Yes
PUTReplace entire resourceβœ… Yes
PATCHUpdate partial resourceβœ… Yes
DELETERemove dataOptional

πŸ’Ύ Client-Side Storage

Save data in the browser without a server

FeaturelocalStoragesessionStorageCookies
LifetimeForever (manual clear)Tab closed β†’ goneSet expiry
Size~5MB~5MB~4KB
Sent to server?❌ No❌ Noβœ… Yes (auto)
Accessible via JS?βœ… Yesβœ… Yesβœ… Yes
// ── localStorage ──
localStorage.setItem("username", "Aarav");
let user = localStorage.getItem("username"); // "Aarav"
localStorage.removeItem("username");
localStorage.clear(); // removes everything

// Store objects (must stringify!)
const prefs = { theme: "dark", lang: "en" };
localStorage.setItem("prefs", JSON.stringify(prefs));
const saved = JSON.parse(localStorage.getItem("prefs"));
console.log(saved.theme); // "dark"

// ── sessionStorage ── (same API, dies with tab)
sessionStorage.setItem("token", "abc123");
let tok = sessionStorage.getItem("token");

// ── JWT (JSON Web Token) ──
// Structure: header.payload.signature
// Used for authentication β€” store in memory or httpOnly cookie
// NEVER store JWT in localStorage if it's super sensitive (XSS risk)

πŸ”„ The JavaScript Event Loop

How JavaScript handles async operations under the hood

🎭 The Cast of Characters

  • Call Stack β€” where your code runs (LIFO: Last In, First Out)
  • Web APIs β€” browser features (setTimeout, fetch, DOM events)
  • Callback Queue (Macrotask) β€” setTimeout, setInterval callbacks wait here
  • Microtask Queue β€” Promise callbacks, queueMicrotask (higher priority!)
  • Event Loop β€” the manager: moves tasks from queue to stack when stack is empty
console.log("1 β€” Start");              // Call Stack (sync)

setTimeout(() => {
  console.log("2 β€” setTimeout");       // Macrotask Queue
}, 0);

Promise.resolve().then(() => {
  console.log("3 β€” Promise");          // Microtask Queue (higher priority!)
});

console.log("4 β€” End");               // Call Stack (sync)

// OUTPUT ORDER:
// 1 β€” Start
// 4 β€” End
// 3 β€” Promise    ← microtask runs BEFORE macrotask
// 2 β€” setTimeout ← macrotask runs last

// Why? Event Loop checks Microtask Queue first
// before moving to the next Macrotask!

βœ… Key Takeaway

Execution order: Synchronous β†’ Microtasks (Promises) β†’ Macrotasks (setTimeout). This is one of the most common JS interview topics!

πŸŽ“ Interview Questions Set 1

Top JS interview questions β€” Fresher to Mid-Level

Q1. What is JavaScript? Is it compiled or interpreted? β–Ό
JavaScript is a lightweight, interpreted (JIT-compiled in modern engines), single-threaded scripting language. It's primarily used for building interactive web pages but now also powers servers (Node.js), mobile apps (React Native), and desktop apps (Electron).
Q2. What is a closure? Give an example. β–Ό
A closure is a function that remembers its outer variables even when called outside the parent scope.

function makeCounter() { let count = 0; return () => ++count; }
const c = makeCounter(); c(); // 1, c(); // 2
Q3. What is the difference between null and undefined? β–Ό
undefined means a variable has been declared but not assigned any value. null is an intentional empty value β€” the developer explicitly set it to "nothing". typeof null === "object" is a historical bug.
Q4. Explain prototype and prototype chain. β–Ό
Every JS object has an internal link to another object called its prototype. When you access a property, JS looks on the object first; if not found, it looks up the prototype chain until it reaches null. This is JavaScript's inheritance mechanism.
Q5. What is debounce vs throttle? β–Ό
Debounce: delays the function until the user stops triggering it (e.g., search input β€” wait until user stops typing). Throttle: limits the function to run at most once per interval (e.g., scroll event β€” run max once every 100ms).

🎯 Interview Practice Tasks

  1. Write a deep clone function without using JSON.parse/stringify
  2. Implement Array.prototype.map from scratch
  3. Explain what this refers to in 5 different scenarios

✏️ Practice Quiz 1

Test your knowledge β€” Beginner Level