JavaScript


1. Getting Started

Console

console.log("Hello world!");
console.warn("hello %s", "CheatSheets.zip");
console.error(new Error("Oops!"));

Variables

let x = null;
let name = "Tammy";
const found = false;
var a;
console.log(a); // => undefined

Numbers

let amount = 6;
let price = 4.99;

Strings

let singleQuotes = "Wheres my bandit hat?";
let doubleQuotes = "Wheres my bandit hat?";
let backTicks = `Wheres my bandit hat? ${some_value}`;
console.log(singleQuotes.length); // => 21

String Interpolation

let age = 7;
"Tommy is " + age + " years old."; // Concatenation
`Tommy is ${age} years old.`; // Interpolation

Comments

// Single line comment
/*
  Multi-line
  comment
*/

2. Operators

Arithmetic

5 + 5; // 10  Addition
10 - 5; // 5   Subtraction
5 * 10; // 50  Multiplication
10 / 5; // 2   Division
10 % 5; // 0   Modulo

Assignment

let number = 100;
number = number + 10;
number += 10;
console.log(number); // => 120

Comparison

1 > 3; // false
3 > 1; // true
250 >= 250; // true
1 === 1; // true
1 === 2; // false
1 === "1"; // false

Logical

true || false; // true
10 > 5 || 10 > 20; // true
false || false; // false

true && true; // true
1 > 2 && 2 > 1; // false
true && false; // false

let lateToWork = true;
let oppositeValue = !lateToWork; // false

3. Conditionals

if / else if / else

const size = 10;
if (size > 100) {
  console.log("Big");
} else if (size > 20) {
  console.log("Medium");
} else if (size > 4) {
  console.log("Small");
} else {
  console.log("Tiny");
}

Ternary Operator

var x = 1;
result = x == 1 ? true : false;

switch Statement

const food = "salad";
switch (food) {
  case "oyster":
    console.log("The taste of the sea");
    break;
  case "pizza":
    console.log("A delicious pie");
    break;
  default:
    console.log("Enjoy your meal");
}

Object Lookup

const food = "salad";
const foods = {
  oyster: "The taste of the sea",
  pizza: "A delicious pie",
};
console.log(foods[food] || "Enjoy your meal");

4. Functions

Function Declaration

function add(num1, num2) {
  return num1 + num2;
}
add(3, 6); // 9

Function Expression

const dog = function () {
  return "Woof!";
};

Arrow Functions (ES6)

// With two arguments
const sum = (param1, param2) => {
  return param1 + param2;
};

// With no arguments
const printHello = () => {
  console.log("hello");
};

// With a single argument
const checkWeight = (weight) => {
  console.log(`Weight : ${weight}`);
};

// Concise — implicit return
const multiply = (a, b) => a * b;

Return Keyword

// With return
function sum(num1, num2) {
  return num1 + num2;
}
// Without return — returns undefined
function sum(num1, num2) {
  num1 + num2;
}

Key Differences

Feature Function Arrow
Own this ✅ ❌
Own arguments ✅ ❌
Can use new ✅ ❌
Hoisted declaration ✅ ❌
Concise syntax ❌ ✅

arguments Object

Normal functions have arguments:

function test() {
  console.log(arguments); // [10, 20, 30]
}
test(10, 20, 30);

Arrow functions don't, but can access an outer function's arguments:

function outer() {
  const inner = () => {
    console.log(arguments[0]); // 100
  };
  inner();
}
outer(100);

Arrow Function Return Trap

(x) => x + 5; // ✅ implicit return
(x) => {
  return x + 5;
}; // ✅ explicit return
(x) => {
  x + 5;
}; // ❌ returns undefined

Functions as First-Class Citizens

Functions can be stored in variables and passed as arguments:

let plusFive = (number) => {
  return number + 5;
};
let f = plusFive;
f(9); // 14

5. Scope

Function Scope

function myFunction() {
  var pizzaName = "Margarita";
  // Code here can use pizzaName
}
// Code here can't use pizzaName

Block Scope

const isLoggedIn = true;
if (isLoggedIn == true) {
  const statusMessage = "Logged in.";
}
// Uncaught ReferenceError...
console.log(statusMessage);

Global Variables

const color = "blue";
function printColor() {
  console.log(color);
}
printColor(); // => blue

Scope Chain

let x = 10; // Global

function outer() {
  let y = 20; // Function scope

  function inner() {
    let z = 30;
    console.log(x); // 10
    console.log(y); // 20
    console.log(z); // 30
  }

  inner();
}

outer();

inner() looks in its own scope first, then outer, then global — this is the scope chain.

Lexical Scoping

JavaScript resolves variables based on where the function is defined, not where it's called.

let x = 10;

function outer() {
  let x = 20;

  function inner() {
    console.log(x); // 20 — found in outer scope
  }

  inner();
}

Shadowing

A variable in an inner scope can have the same name as one in an outer scope.

let x = 10;

function test() {
  let x = 20;
  console.log(x); // 20 — inner x wins
}

test();
console.log(x); // 10 — outer x unchanged

6. var vs let vs const

let — Block Scoped

let count;
console.log(count); // => undefined
count = 10;
console.log(count); // => 10

const — Block Scoped, Cannot Reassign

const numberOfColumns = 4;
numberOfColumns = 8; // TypeError: Assignment to constant...

let vs var Scope

for (let i = 0; i < 3; i++) {
  // i accessible ✔️
}
// i not accessible ❌

for (var i = 0; i < 3; i++) {
  // i accessible ✔️
}
// i accessible ✔️ — var leaks out

var is scoped to the nearest function block. let is scoped to the nearest enclosing block.

Hoisting

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

console.log(b); // ❌ ReferenceError
let b = 10;

var is hoisted with undefined. let/const are in the Temporal Dead Zone (TDZ) until declaration.

var:       scope starts → a = undefined → a = 10 (usable immediately)
let/const: scope starts → TDZ → declaration → usable

Function Hoisting

sayHello(); // ✅ "Hello"
function sayHello() {
  console.log("Hello");
}

sayHello2(); // ❌ ReferenceError
const sayHello2 = function () {
  console.log("Hello");
};

const with Objects

const user = { name: "Ayrus" };
user.name = "John"; // ✅ — modifying the object
user = {}; // ❌ — can't reassign the variable

const = can't change the reference, but the referenced object can still change.


7. Arrays

Creating Arrays

const fruits = ["apple", "orange", "banana"];
const data = [1, "chicken", false]; // Different types

Property & Index

const numbers = [1, 2, 3, 4];
numbers.length; // 4

const myArray = [100, 200, 300];
console.log(myArray[0]); // 100
console.log(myArray[1]); // 200

Mutating Methods

Method Action Position
push add end
pop remove end
unshift add start
shift remove start
const cart = ["apple", "orange"];
cart.push("pear"); // add to end

const fruits = ["apple", "orange", "banana"];
fruits.pop(); // remove from end => "banana"

let cats = ["Bob", "Willy", "Mini"];
cats.shift(); // remove from start => "Bob"

let dogs = ["Bob"];
dogs.unshift("Willy"); // add to start

Array.concat()

const numbers = [3, 2, 1];
[4].concat(numbers); // [4, 3, 2, 1]
numbers.concat(4); // [3, 2, 1, 4]

slice() vs splice()

// slice — copy/extract, original unchanged
const a = [10, 20, 30, 40, 50];
a.slice(1, 4); // [20, 30, 40] — end excluded

// splice — modifies original
const b = [10, 20, 30, 40, 50];
b.splice(1, 2); // removed: [20, 30], b is now [10, 40, 50]

// splice can also insert
let c = [10, 20, 50];
c.splice(2, 0, 30, 40); // [10, 20, 30, 40, 50]
slice  → take a slice 🍕 → original unchanged
splice → modify/remove    → original changes

Destructuring

const [a, b, c] = [10, 20, 30];
const [, second] = [10, 20, 30]; // skip first
const [first, ...rest] = [10, 20, 30, 40];
// first = 10, rest = [20, 30, 40]

8. Higher-Order Functions & Iterators

map() — Transform Every Element

const members = ["Taylor", "Donald", "Don"];
const announcements = members.map((member) => {
  return member + " joined the contest.";
});

filter() — Select Elements

const randomNumbers = [4, 11, 42, 14, 39];
const filteredArray = randomNumbers.filter((n) => {
  return n > 5;
});

reduce() — Combine Into One Value

const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((accumulator, curVal) => {
  return accumulator + curVal;
}, 0);
console.log(sum); // 10

Step-by-step:

       total    n     return
         0      1  →    1
         1      2  →    3
         3      3  →    6
         6      4  →   10

forEach() — Perform Action on Each

const numbers = [28, 77, 45, 99, 27];
numbers.forEach((number) => {
  console.log(number);
});

Comparison

Method Purpose
map() Transform every element
filter() Select elements
reduce() Combine into one value
forEach() Perform action on each

Real-World reduce()

const users = [
  { name: "A", age: 20 },
  { name: "B", age: 25 },
];

const result = users.reduce((obj, user) => {
  obj[user.name] = user.age;
  return obj;
}, {});
// { A: 20, B: 25 }

Callbacks

A callback is a function passed into another function as an argument.

const isEven = (n) => {
  return n % 2 == 0;
};
let printMsg = (evenFunc, num) => {
  const isNumEven = evenFunc(num);
  console.log(`${num} is an even number: ${isNumEven}.`);
};
printMsg(isEven, 4);

9. Objects

Accessing Properties

const apple = {
  color: "Green",
  price: { bulk: "$3/kg", smallQty: "$4/kg" },
};
console.log(apple.color); // => Green
console.log(apple.price.bulk); // => $3/kg

Non-existent Properties

const classElection = { date: "January 12" };
console.log(classElection.place); // undefined

Mutable

const student = {
  name: "Sheldon",
  score: 100,
  grade: "A",
};
delete student.score;
student.grade = "F";
student = {}; // TypeError: Assignment to constant variable.

Shorthand Creation

const activity = "Surfing";
const beach = { activity };
console.log(beach); // { activity: 'Surfing' }

Destructuring

const { name, age } = { name: "John Doe", age: 8 };
console.log(name); // "John Doe"

// Nested destructuring
const {
  address: { city },
} = {
  address: { city: "Chennai" },
};

Object Rest

const { name, ...details } = {
  name: "Ayrus",
  age: 23,
  city: "Chennai",
};
// name = "Ayrus", details = { age: 23, city: "Chennai" }

Spread Operator

const a = { name: "Ayrus" };
const b = { ...a, age: 23 }; // shallow copy + add

Objects as Arguments (Pass by Reference)

const origNum = 8;
const origObj = { color: "blue" };
const changeItUp = (num, obj) => {
  num = 7;
  obj.color = "red";
};
changeItUp(origNum, origObj);
console.log(origNum); // 8 — primitives passed by value
console.log(origObj.color); // "red" — objects passed by reference

Getters and Setters

const myCat = {
  _name: "Dottie",
  get name() {
    return this._name;
  },
  set name(newName) {
    this._name = newName;
  },
};
console.log(myCat.name);
myCat.name = "Yankee";

Factory Functions

const dogFactory = (name, age, breed) => {
  return {
    name,
    age,
    breed,
    bark() {
      console.log("Woof!");
    },
  };
};

10. this Keyword

Normal Function — this Depends on How It's Called

const cat = {
  name: "Pipey",
  whatName() {
    return this.name;
  },
};
console.log(cat.whatName()); // => Pipey

But if you extract the function:

const fn = cat.whatName;
fn(); // undefined — no object before the call

Arrow Function — this Comes from Surrounding Scope

const person = {
  name: "Ayrus",
  greet: () => {
    console.log(this.name);
  },
};
person.greet(); // undefined — arrow takes outer this

Golden Rule

Normal function → this depends on HOW it is called.
Arrow function → this comes from WHERE it is created.


11. call(), apply(), bind()

const person = { name: "Ayrus" };

function greet(age, city) {
  console.log(this.name, age, city);
}

greet.call(person, 23, "Chennai"); // call — args individually
greet.apply(person, [23, "Chennai"]); // apply — args as array
const fn = greet.bind(person, 23, "Chennai"); // bind — returns new fn
fn();
Method Executes immediately? Arguments
call() ✅ a, b
apply() ✅ [a, b]
bind() ❌ a, b

12. Closures

A closure is a function that remembers variables from its outer scope, even after the outer function has finished.

Closure = function + its remembered outer scope

function outer() {
  let count = 0;
  return function () {
    count++;
    console.log(count);
  };
}

let counter = outer();
counter(); // 1
counter(); // 2
counter(); // 3

Separate Closure Environments

Every call to the outer function creates a new environment.

let a = outer();
let b = outer();
a(); // 1
a(); // 2
b(); // 1 — separate count

The Famous Loop Problem

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 10);
}
// 3 3 3 — var shares one i

for (let j = 0; j < 3; j++) {
  setTimeout(() => console.log(j), 10);
}
// 0 1 2 — let creates separate i per iteration

13. Loops

for Loop

for (let i = 0; i < 4; i += 1) {
  console.log(i);
}
// => 0, 1, 2, 3

while Loop

let i = 0;
while (i < 5) {
  console.log(i);
  i++;
}

do…while

let x = 0,
  i = 0;
do {
  x = x + i;
  console.log(x);
  i++;
} while (i < 5);

for...in (Keys/Indexes)

const fruits = ["apple", "orange", "banana"];
for (let index in fruits) {
  console.log(index, fruits[index]);
}
// 0 apple, 1 orange, 2 banana

for...of (Values)

const fruits = ["apple", "orange", "banana"];
for (let fruit of fruits) {
  console.log(fruit);
}
// apple, orange, banana

break & continue

for (let i = 0; i < 99; i++) {
  if (i > 5) break; // stop loop
  console.log(i);
}

for (let i = 0; i < 10; i++) {
  if (i === 3) continue; // skip this iteration
  console.log(i);
}

14. Set

const emptySet = new Set();
const setObj = new Set([1, true, "hi"]);

setObj.add("a");
setObj.delete("a");
setObj.has(1); // true
setObj.size; // number of elements
setObj.clear(); // remove all

setObj.forEach(function (value) {
  console.log(value);
});

Remove Duplicates from Array

const arr = [1, 2, 2, 3, 3];
const unique = [...new Set(arr)]; // [1, 2, 3]

15. Map

A Map stores key → value pairs with any key type.

const map = new Map();

map.set("name", "Ayrus");
map.set("age", 23);

console.log(map.get("name")); // "Ayrus"
map.has("name"); // true
map.delete("name");
map.clear();

Objects as keys:

const obj = { id: 1 };
map.set(obj, "User data");
console.log(map.get(obj)); // "User data"

When to Use What

Object → structured entity/data
Map    → dynamic key-value collection
Set    → unique values

16. Type Coercion

+ is Special

5 + "5"; // "55" — string concatenation
5 - "5"; // 0   — numeric conversion
5 * "5"; // 25  — numeric conversion
5 / "5"; // 1   — numeric conversion

Boolean Coercion

Number(true); // 1
Number(false); // 0

"5" + true; // "5true" — string concatenation wins
"5" - true; // 4       — numeric: 5 - 1
true + true; // 2

Array Coercion

[5] *
  [2][(5, 2)] * // 10  — "5" → 5, "2" → 2
  [2]; // NaN — "5,2" → NaN

17. == vs ===

0 == false; // true  — coercion
0 === false; // false — different type
1 == "1"; // true  — coercion
1 === "1"; // false — different type
null == undefined; // true  — special rule
null === undefined; // false
"0" == false; // true
"0" === false; // false

== checks value after coercion. === checks both value and type. Prefer ===.

[] == false Explained

[] == false → [] == 0 → "" == 0 → 0 == 0 → true

But Boolean([]) is true — different operation.


18. Truthy & Falsy

Falsy Values

(false, 0, -0, 0n, "", null, undefined, NaN);

Everything else is truthy, including [], {}, "0", "false".


19. null vs undefined vs NaN

undefined → value not assigned
null      → intentionally empty
NaN       → not a number (but typeof is "number")
typeof undefined; // "undefined"
typeof null; // "object"  — historical bug
typeof NaN; // "number"
NaN === NaN; // false — use Number.isNaN()

20. Primitive vs Reference

// Primitives — copied by value
let a = 10;
let b = a;
b = 20;
console.log(a); // 10 — unchanged

// Objects — copied by reference
let obj1 = { name: "Ayrus" };
let obj2 = obj1;
obj2.name = "John";
console.log(obj1.name); // "John" — changed!

21. Shallow Copy vs Deep Copy

Spread — Shallow Copy

let a = { name: "Ayrus", address: { city: "Chennai" } };
let b = { ...a };

b.address.city = "Mumbai";
console.log(a.address.city); // "Mumbai" — nested objects shared!

structuredClone() — Deep Copy

let b = structuredClone(a);
b.address.city = "Mumbai";
console.log(a.address.city); // "Chennai" — independent

22. Spread & Rest

Spread — Unpack

const a = [1, 2, 3];
const b = [...a]; // copy
const c = [...a, ...[4, 5]]; // combine

Rest — Collect

function sum(...numbers) {
  console.log(numbers); // [10, 20, 30]
}
sum(10, 20, 30);

Rest must always be the last element.


23. Classes

Class & Constructor

class Song {
  constructor(title, artist) {
    this.title = title;
    this.artist = artist;
  }
  play() {
    console.log("Playing!");
  }
}
const mySong = new Song("Bohemian Rhapsody", "Queen");

Static Methods

class Dog {
  constructor(name) {
    this._name = name;
  }
  introduce() {
    console.log("This is " + this._name);
  }
  static bark() {
    console.log("Woof!");
  }
}
Dog.bark(); // static — called on class, not instance

extends & super

class Media {
  constructor(info) {
    this.publishDate = info.publishDate;
    this.name = info.name;
  }
}
class Song extends Media {
  constructor(songData) {
    super(songData);
    this.artist = songData.artist;
  }
}

24. Prototypes & Prototype Chain

If JavaScript can't find a property on an object, it looks up the prototype chain.

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

Person.prototype.greet = function () {
  console.log("Hello " + this.name);
};

const a = new Person("Ayrus");
a.greet(); // Hello Ayrus

Own property wins over prototype property.


25. Promises

stateDiagram-v2 [*] --> Pending Pending --> Fulfilled : resolve(value) ✅ Pending --> Rejected : reject(error) ❌ Fulfilled --> [*] : .then() Rejected --> [*] : .catch()

JavaScript Event Loop Architecture

flowchart TD subgraph Engine["⚡ JavaScript Engine (V8)"] CS["📚 Call Stack
(LIFO - Synchronous Execution)"] Heap["🧠 Memory Heap
(Objects & Variables)"] end subgraph WebAPIs["🌐 Browser / Node APIs"] Timer["setTimeout / setInterval"] Fetch["fetch() / AJAX HTTP"] DOM["DOM Events (click, scroll)"] end subgraph Queues["📬 Asynchronous Task Queues"] Micro["⭐ Microtask Queue (High Priority)
• Promise.then() / .catch()
• queueMicrotask()
• MutationObserver"] Macro["📋 Macrotask / Callback Queue
• setTimeout / setInterval
• I/O / setImmediate"] end CS -->|"Offloads Async"| WebAPIs WebAPIs -->|"Promise resolves"| Micro WebAPIs -->|"Timer expires / Event fires"| Macro Micro -->|"Event Loop pushes when Stack is empty"| CS Macro -->|"Event Loop pushes after all Microtasks clear"| CS
const promise = new Promise((resolve, reject) => {
  const res = true;
  if (res) {
    resolve("Resolved!");
  } else {
    reject(Error("Error"));
  }
});
promise.then(
  (res) => console.log(res),
  (err) => console.error(err),
);

.then() and .catch()

promise.then((res) => console.log(res)).catch((err) => console.error(err));
resolve() → .then()  ✅
reject()  → .catch() ❌

Promise Chaining

The value returned from one .then() becomes the input to the next.

Promise.resolve(10)
  .then((x) => x + 5) // 15
  .then((x) => x * 2) // 30
  .then((x) => console.log(x)); // 30

Error in chain — skips to .catch():

Promise.resolve(10)
  .then((x) => {
    throw new Error("Oops");
  })
  .then(() => console.log("skipped"))
  .catch((err) => console.log(err.message)); // "Oops"

Promise.all() & Promise.allSettled()

// All must resolve
Promise.all([promise1, promise2]).then((res) => {
  console.log(res); // [result1, result2]
});

// All settle (resolve or reject)
Promise.allSettled([promise1, promise2]).then((res) => {
  console.log(res[0].status); // "fulfilled" or "rejected"
});

setTimeout()

const loginAlert = () => {
  console.log("Login");
};
setTimeout(loginAlert, 6000);

26. Async / Await

async — Always Returns a Promise

async function greet() {
  return "Hello";
}
greet().then((value) => console.log(value)); // "Hello"

await — Wait for Promise

async function main() {
  const result = await getData();
  console.log(result);
}

Execution Order

console.log("A");
async function test() {
  let x = await Promise.resolve(10);
  console.log(x + 5);
}
test();
console.log("B");
// Output: A, B, 15

await pauses the async function but doesn't block JavaScript.

Error Handling with try/catch

async function getData() {
  try {
    const response = await fetch(url);
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.log("Something went wrong");
  }
}

27. Error Handling

try {
  let user = JSON.parse('{ "age": 30 }');
  console.log(user.name); // undefined
} catch (e) {
  console.error("Invalid JSON data!");
}

throw

function divide(a, b) {
  if (b === 0) {
    throw new Error("Cannot divide by zero");
  }
  return a / b;
}

try {
  divide(10, 0);
} catch (error) {
  console.log(error.message); // "Cannot divide by zero"
}

throw immediately stops the function. Properties: error.message, error.name, error.stack.


28. Modules

ES Modules — export / import

// myMath.js
export default function add(x, y) {
  return x + y;
}
export function subtract(x, y) {
  return x - y;
}
// main.js
import add, { subtract } from "./myMath.js";
export { add }       → import { add }     // Named — needs { }
export default add   → import add         // Default — no { }

CommonJS — module.exports / require

// myMath.js
module.exports = { add, subtract, multiply };

// main.js
const myMath = require("./myMath.js");
console.log(myMath.add(6, 2)); // 8

29. Fetch API & HTTP Requests

JSON

{
  "name": "Rick",
  "id": "11A",
  "level": 4
}

XMLHttpRequest

const xhr = new XMLHttpRequest();
xhr.open("GET", "mysite.com/getjson");

GET

const req = new XMLHttpRequest();
req.responseType = "json";
req.open("GET", "/getdata?id=65");
req.onload = () => {
  console.log(req.response);
};
req.send();

POST

const data = {
  fish: "Salmon",
  weight: "1.5 KG",
  units: 5,
};
const xhr = new XMLHttpRequest();
xhr.open("POST", "/inventory/add");
xhr.responseType = "json";
xhr.send(JSON.stringify(data));

Fetch API

// GET
const response = await fetch("/api/users");
const data = await response.json();

// POST
const response = await fetch("/api/users", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ name: "Ayrus", age: 23 }),
});

Important: Check response.ok

fetch(url)
  .then((response) => {
    if (response.ok) {
      return response.json();
    }
    throw new Error("Request failed!");
  })
  .then((jsonResponse) => console.log(jsonResponse));

Async Await with Fetch

const getSuggestions = async () => {
  try {
    const response = await fetch(endpoint, { cache: "no-cache" });
    if (response.ok) {
      const jsonResponse = await response.json();
    }
  } catch (error) {
    console.log(error);
  }
};

30. DOM Manipulation

Selecting Elements

document.getElementById("title");
document.querySelector("#title"); // id
document.querySelector(".text"); // class
document.querySelectorAll("p"); // all matching

Modifying Elements

const title = document.querySelector("#title");
title.textContent = "JavaScript";
title.style.color = "red";
title.classList.add("active");
title.classList.remove("active");
title.classList.toggle("active");

textContent vs innerHTML

box.textContent = "<h1>Hello</h1>"; // plain text
box.innerHTML = "<h1>Hello</h1>"; // parsed HTML

31. Events, Bubbling & Delegation

addEventListener

btn.addEventListener("click", (event) => {
  console.log(event.type); // "click"
  console.log(event.target); // clicked element
});

Event Bubbling

Events travel upward from target through ancestors.

parent.addEventListener("click", () => console.log("Parent"));
child.addEventListener("click", () => console.log("Child"));
// Click child → "Child" then "Parent"

Event Delegation

One listener on the parent handles all children:

list.addEventListener("click", (event) => {
  if (event.target.tagName === "LI") {
    console.log(event.target.textContent);
  }
});

preventDefault() vs stopPropagation()

Method Stops what?
preventDefault() Browser's default action
stopPropagation() Event traveling through DOM

32. Optional Chaining & Nullish Coalescing

Optional Chaining ?.

const obj = { name: "John Doe", age: 8 };
console.log(obj?.address); // undefined (no error)
console.log(obj.address?.city); // undefined (no error)

Nullish Coalescing ??

null ?? "I win"; // "I win"
undefined ?? "Me too"; // "Me too"
false ?? "I lose"; // false — not null/undefined
0 ?? "I lose again"; // 0

?? vs ||

let age = 0;
console.log(age || 18); // 18 — 0 is falsy
console.log(age ?? 18); // 0  — 0 is not null/undefined

&& and || Return Values

0 || 10; // 10
"Hello" || "World"; // "Hello"
true && "Hello"; // "Hello"
false && "Hello"; // false
isLoggedIn && showDashboard(); // conditional execution

33. Debouncing & Throttling

Debounce — Wait Until They Stop

function debounce(fn, delay) {
  let timer;
  return function (...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };
}

Use case: Search input — wait until user stops typing.

Throttle — Limit Frequency

Allow function to run at most once per interval.

Use case: Scroll events.

Feature Debounce Throttle
Idea Wait for silence Limit frequency
Search ⭐⭐⭐ —
Scroll — ⭐⭐⭐

34. localStorage & sessionStorage

localStorage.setItem("name", "Ayrus");
localStorage.getItem("name"); // "Ayrus"
localStorage.removeItem("name");
localStorage.clear();

Stores Strings Only

const user = { name: "Ayrus", age: 23 };
localStorage.setItem("user", JSON.stringify(user));
const data = JSON.parse(localStorage.getItem("user"));

Comparison

Feature localStorage sessionStorage
Survives page refresh? ✅ ✅
Survives closing browser/tab? ✅ ❌

35. Object Reference & Equality

{} === {}       // false — different objects
[] === []       // false — different arrays
[1] === [1]     // false — different references

const a = [1, 2];
const b = a;
a === b         // true — same reference
Object → reference comparison
Primitive → value comparison

36. IIFE

A function that runs immediately after it's defined:

(function () {
  let x = 10;
  console.log(x); // 10
})();
// x is not accessible here

Creates a private scope — essential before let/const existed.


🧠 Learning Path

Variables → Scope → Execution Context → Call Stack → Closures → Async JavaScript → Event Loop