Introduction to JavaScript
Beginner · 5 min read
JavaScript (JS) is a lightweight, interpreted, multi-paradigm programming language. It runs in the browser (client-side) and on servers via Node.js. It is the only language natively supported by all browsers and is essential for building interactive web experiences.
Where JS Runs
- Browser: Manipulate the DOM, handle events, call APIs
- Node.js: Server-side apps, CLIs, build tools
- React Native / Electron: Mobile and desktop apps
Adding JavaScript to a Page
// 1. Inline (avoid for large scripts)
<button onclick="alert('Hi!')">Click me</button>
// 2. Internal script tag
<script>
console.log('Hello from <script> tag');
</script>
// 3. External file (preferred) — place before </body>
<script src="app.js" defer></script>
💡 defer downloads the script in parallel with HTML parsing and executes it after the document is fully parsed — best practice for most scripts.
Variables & Data Types
Beginner · 8 min read
// Three ways to declare variables
var x = 10; // function-scoped, hoisted — avoid in modern JS
let y = 20; // block-scoped, re-assignable
const z = 30; // block-scoped, cannot be reassigned
// Primitive types
const num = 42; // Number
const big = 9007199254740993n; // BigInt
const str = "Hello"; // String
const bool = true; // Boolean
const nil = null; // Null (intentional absence)
const undef = undefined; // Undefined (not yet assigned)
const sym = Symbol('id'); // Symbol (unique key)
// Reference types
const arr = [1, 2, 3];
const obj = { name: 'Aftab', age: 25 };
const fn = () => 'I am a function';
// typeof checks
typeof 42 // 'number'
typeof 'hello' // 'string'
typeof true // 'boolean'
typeof undefined // 'undefined'
typeof null // 'object' ← famous JS quirk!
typeof [] // 'object'
typeof {} // 'object'
typeof function(){} // 'function'
// Type coercion pitfalls
'5' + 3 // '53' ← string concatenation
'5' - 3 // 2 ← numeric subtraction
null == undefined // true ← loose equality
null === undefined // false ← strict equality (use this!)
⚠️ Always use === (strict equality) instead of == to avoid unexpected type coercion bugs.
Operators & Expressions
Beginner · 6 min read
// Arithmetic
10 + 3 // 13 — addition
10 - 3 // 7 — subtraction
10 * 3 // 30 — multiplication
10 / 3 // 3.333...
10 % 3 // 1 — modulus (remainder)
2 ** 10 // 1024 — exponentiation
// Comparison (always prefer ===)
5 === 5 // true
5 !== '5' // true
5 > 3 // true
// Logical
true && false // false — AND
true || false // true — OR
!true // false — NOT
// Nullish coalescing (ES2020)
const name = null ?? 'Anonymous'; // 'Anonymous'
const port = 0 ?? 3000; // 0 (0 is NOT null/undefined)
// Optional chaining (ES2020)
const city = user?.address?.city; // undefined instead of TypeError
const len = arr?.[0]?.length;
// Logical assignment (ES2021)
x ||= 10; // x = x || 10
x &&= 20; // x = x && 20
x ??= 30; // x = x ?? 30
// Template literals (backticks)
const msg = `Hello, ${name}! You are ${age} years old.`;
const multiline = `
Line 1
Line 2
`;
Control Flow
Beginner · 8 min read
// if / else if / else
if (score >= 90) {
grade = 'A';
} else if (score >= 75) {
grade = 'B';
} else {
grade = 'C';
}
// Ternary operator
const msg = age >= 18 ? 'Adult' : 'Minor';
// switch
switch (day) {
case 'Mon':
case 'Tue': console.log('Weekday'); break;
case 'Sat':
case 'Sun': console.log('Weekend'); break;
default: console.log('Unknown');
}
// for loop
for (let i = 0; i < 5; i++) { console.log(i); }
// for...of (iterate values)
for (const item of ['a', 'b', 'c']) { console.log(item); }
// for...in (iterate object keys)
for (const key in obj) { console.log(key, obj[key]); }
// while
let n = 0;
while (n < 5) { n++; }
// do...while (executes at least once)
do { n++; } while (n < 10);
// break / continue
for (let i = 0; i < 10; i++) {
if (i === 3) continue; // skip 3
if (i === 7) break; // stop at 7
console.log(i);
}
Functions
Beginner · 10 min read
// Function declaration (hoisted)
function greet(name) {
return `Hello, ${name}!`;
}
// Function expression
const add = function(a, b) { return a + b; };
// Arrow function (ES6) — no own 'this'
const multiply = (a, b) => a * b;
const square = n => n * n; // single param: no parens needed
const noArg = () => 'hello';
// Default parameters
function connect(host = 'localhost', port = 3000) {
console.log(`Connecting to ${host}:${port}`);
}
// Rest parameters (...args)
function sum(...nums) {
return nums.reduce((acc, n) => acc + n, 0);
}
sum(1, 2, 3, 4); // 10
// Higher-order functions
function applyTwice(fn, x) { return fn(fn(x)); }
applyTwice(x => x * 2, 3); // 12
// Immediately Invoked Function Expression (IIFE)
(function() {
console.log('Runs immediately');
})();
// Pure function — no side effects, same input → same output
const pureAdd = (a, b) => a + b;
Scope & Closures
Intermediate · 10 min read
Scope determines variable visibility. Closures let inner functions access outer function variables even after the outer function has returned.
// Global, function, block scope
let global = 'I am global';
function outer() {
let outerVar = 'outer';
function inner() {
let innerVar = 'inner';
console.log(global); // accessible
console.log(outerVar); // accessible (closure)
console.log(innerVar); // accessible
}
inner();
// innerVar is NOT accessible here
}
// Practical closure: counter factory
function makeCounter(start = 0) {
let count = start;
return {
increment: () => ++count,
decrement: () => --count,
value: () => count
};
}
const counter = makeCounter(10);
counter.increment(); // 11
counter.value(); // 11
// Closure for data privacy (module pattern)
const bankAccount = (() => {
let balance = 0; // private
return {
deposit: amt => { balance += amt; },
withdraw: amt => { balance -= amt; },
getBalance: () => balance
};
})();
Objects & Prototypes
Intermediate · 12 min read
// Object literal
const user = {
name: 'Aftab',
age: 28,
greet() { return `Hi, I'm ${this.name}`; } // shorthand method
};
// Property access
user.name; // dot notation
user['age']; // bracket notation (dynamic keys)
// Computed property names
const key = 'role';
const obj = { [key]: 'admin' }; // { role: 'admin' }
// Object methods
Object.keys(user); // ['name', 'age', 'greet']
Object.values(user); // ['Aftab', 28, [Function]]
Object.entries(user); // [['name','Aftab'], ...]
Object.assign({}, user, { age: 29 }); // shallow copy + override
const clone = { ...user }; // spread (also shallow copy)
// Deep clone
const deep = structuredClone(user); // ES2022 native deep clone
// Prototype chain
const animal = { eat() { return 'nom nom'; } };
const dog = Object.create(animal);
dog.bark = () => 'woof';
dog.eat(); // 'nom nom' — inherited from animal
// Object.freeze / seal
Object.freeze(obj); // prevent ALL changes
Object.seal(obj); // allow update but not add/delete
Arrays & Methods
Intermediate · 12 min read
const nums = [1, 2, 3, 4, 5];
// Mutating methods
nums.push(6); // add to end → [1,2,3,4,5,6]
nums.pop(); // remove from end
nums.unshift(0); // add to start → [0,1,2,3,4,5]
nums.shift(); // remove from start
nums.splice(2, 1); // remove 1 element at index 2
nums.sort((a, b) => a - b); // numeric sort
nums.reverse();
// Non-mutating (functional) methods
nums.map(n => n * 2); // [2,4,6,8,10] — transform each
nums.filter(n => n % 2 === 0); // [2,4] — keep matching
nums.reduce((acc, n) => acc + n, 0); // 15 — accumulate
nums.find(n => n > 3); // 4 — first match
nums.findIndex(n => n > 3); // 3 — index of first match
nums.some(n => n > 4); // true — any match?
nums.every(n => n > 0); // true — all match?
nums.includes(3); // true
nums.flat(2); // flatten nested arrays (depth 2)
nums.flatMap(n => [n, n * 2]); // map + flatten by 1
nums.slice(1, 3); // [2,3] — non-mutating subset
nums.join(', '); // '1, 2, 3, 4, 5'
// Chaining
const result = [1,2,3,4,5]
.filter(n => n % 2 !== 0) // [1,3,5]
.map(n => n ** 2) // [1,9,25]
.reduce((a, b) => a + b); // 35
Destructuring & Spread
Intermediate · 8 min read
// Array destructuring
const [first, second, ...rest] = [1, 2, 3, 4];
// first=1, second=2, rest=[3,4]
// Skip elements
const [, , third] = ['a', 'b', 'c']; // 'c'
// Object destructuring
const { name, age, city = 'Noida' } = user; // default for missing key
// Rename while destructuring
const { name: userName, age: userAge } = user;
// Nested destructuring
const { address: { street, pin } } = user;
// Function parameter destructuring
function display({ name, age }) {
console.log(`${name} is ${age}`);
}
// Spread operator
const a = [1, 2];
const b = [3, 4];
const c = [...a, ...b]; // [1,2,3,4]
const merged = { ...defaults, ...overrides }; // merge objects
// Swap variables
[x, y] = [y, x];
DOM Manipulation
Intermediate · 12 min read
// Selecting elements
document.getElementById('myId');
document.querySelector('.myClass'); // first match
document.querySelectorAll('p.intro'); // NodeList of all
document.getElementsByClassName('btn'); // live HTMLCollection
// Modifying content
el.textContent = 'Safe text'; // safe, no HTML parsing
el.innerHTML = '<b>Bold</b>'; // parses HTML — XSS risk if user input!
// Modifying styles
el.style.color = '#1a6aff';
el.style.display = 'none';
el.classList.add('active');
el.classList.remove('hidden');
el.classList.toggle('open');
el.classList.contains('active'); // boolean
// Attributes
el.setAttribute('data-id', '42');
el.getAttribute('href');
el.removeAttribute('disabled');
el.dataset.id; // reads data-id attribute
// Creating and inserting elements
const div = document.createElement('div');
div.textContent = 'New element';
div.className = 'card';
document.body.appendChild(div);
parent.insertBefore(div, sibling);
parent.removeChild(child);
el.replaceWith(newEl); // ES6
el.remove(); // ES6
// Traversal
el.parentElement;
el.children; // HTMLCollection of children
el.firstElementChild;
el.lastElementChild;
el.nextElementSibling;
el.previousElementSibling;
Events & Event Loop
Intermediate · 12 min read
// addEventListener (preferred)
btn.addEventListener('click', (e) => {
e.preventDefault(); // stop default (form submit, link)
e.stopPropagation(); // stop bubbling up
console.log('Clicked!', e.target);
});
// Event delegation — attach to parent, handle children
document.getElementById('list').addEventListener('click', (e) => {
if (e.target.matches('li')) {
console.log('Item clicked:', e.target.textContent);
}
});
// Common events
// click, dblclick, mouseover, mouseout, mousemove
// keydown, keyup, keypress
// submit, change, input, focus, blur
// scroll, resize (on window)
// DOMContentLoaded, load (page events)
// Remove listener
function handler(e) { ... }
btn.addEventListener('click', handler);
btn.removeEventListener('click', handler);
// Custom events
const evt = new CustomEvent('orderPlaced', { detail: { id: 42 } });
document.dispatchEvent(evt);
document.addEventListener('orderPlaced', (e) => {
console.log(e.detail.id);
});
// Throttle scroll handler for performance
let ticking = false;
window.addEventListener('scroll', () => {
if (!ticking) {
requestAnimationFrame(() => {
// handle scroll
ticking = false;
});
ticking = true;
}
});
Web Storage & Cookies
Intermediate · 7 min read
// localStorage (5–10 MB, persists across sessions)
localStorage.setItem('token', 'abc123');
const t = localStorage.getItem('token');
localStorage.removeItem('token');
localStorage.clear();
// Store objects as JSON
localStorage.setItem('user', JSON.stringify({ id: 1, name: 'Aftab' }));
const user = JSON.parse(localStorage.getItem('user'));
// sessionStorage (cleared when tab closes)
sessionStorage.setItem('step', '2');
// Cookies (sent to server with every request)
document.cookie = "username=Aftab; path=/; max-age=3600; SameSite=Lax";
function getCookie(name) {
return document.cookie
.split('; ')
.find(r => r.startsWith(name + '='))
?.split('=')[1];
}
Callbacks & Timers
Intermediate · 8 min read
// Callback — a function passed to another function
function fetchData(url, callback) {
// simulate async work
setTimeout(() => callback(null, { data: 'result' }), 1000);
}
fetchData('/api', (err, result) => {
if (err) return console.error(err);
console.log(result);
});
// Timers
const timer = setTimeout(() => {
console.log('Runs once after 2 seconds');
}, 2000);
clearTimeout(timer); // cancel
const interval = setInterval(() => {
console.log('Runs every second');
}, 1000);
clearInterval(interval); // stop
// queueMicrotask — runs before next macrotask
queueMicrotask(() => console.log('microtask'));
// requestAnimationFrame — smooth animations (60fps)
function animate(timestamp) {
// update animation state
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
Promises
Intermediate · 10 min read
A Promise represents an eventual value — either resolved (success) or rejected (failure). Promises solve callback hell by enabling chaining.
// Creating a Promise
const p = new Promise((resolve, reject) => {
const ok = Math.random() > 0.5;
if (ok) resolve('Success!');
else reject(new Error('Failed!'));
});
// Consuming
p.then(result => console.log(result))
.catch(err => console.error(err))
.finally(() => console.log('Done'));
// Promise chaining (avoid nested callbacks)
fetchUser(1)
.then(user => fetchOrders(user.id))
.then(orders => console.log(orders))
.catch(console.error);
// Promise.all — run in parallel, fail fast
const [users, products] = await Promise.all([
fetchUsers(),
fetchProducts()
]);
// Promise.allSettled — wait for all, never rejects
const results = await Promise.allSettled([p1, p2, p3]);
results.forEach(({ status, value, reason }) => {
if (status === 'fulfilled') console.log(value);
else console.error(reason);
});
// Promise.race — resolve/reject with first settled
const first = await Promise.race([p1, timeout(5000)]);
Async / Await
Intermediate · 8 min read
async/await is syntactic sugar over Promises, making async code read like synchronous code.
// async function always returns a Promise
async function getUser(id) {
try {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const user = await res.json();
return user;
} catch (err) {
console.error('getUser failed:', err);
throw err; // re-throw so caller knows
}
}
// Parallel with async/await
async function dashboard() {
const [user, stats] = await Promise.all([
getUser(1),
getStats()
]);
return { user, stats };
}
// Sequential (each awaits previous result)
async function process() {
const order = await createOrder();
const payment = await processPayment(order.id);
await sendConfirmation(payment);
}
// Top-level await (ES2022, in modules only)
const config = await fetchConfig();
Fetch API & AJAX
Intermediate · 10 min read
// GET request
const res = await fetch('/api/users');
const data = await res.json();
// POST with JSON body
const res = await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Aftab', email: 'a@b.com' })
});
// PUT / PATCH / DELETE
await fetch(`/api/users/${id}`, { method: 'DELETE' });
// Upload file with FormData
const form = new FormData();
form.append('file', fileInput.files[0]);
form.append('name', 'avatar');
await fetch('/upload', { method: 'POST', body: form });
// Abort / timeout
const ctrl = new AbortController();
setTimeout(() => ctrl.abort(), 5000); // 5s timeout
await fetch('/api/slow', { signal: ctrl.signal });
// Reusable fetch wrapper
async function api(url, options = {}) {
const defaults = {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${getToken()}`
}
};
const res = await fetch(url, { ...defaults, ...options });
if (!res.ok) throw new Error(`API error: ${res.status}`);
return res.json();
}
ES6 Classes
Intermediate · 10 min read
class Animal {
// Class field (ES2022)
#name; // private field
constructor(name, sound) {
this.#name = name;
this.sound = sound;
}
speak() {
return `${this.#name} says ${this.sound}`;
}
get name() { return this.#name; }
set name(v) { if (v) this.#name = v; }
static create(name, sound) { return new Animal(name, sound); }
}
// Inheritance
class Dog extends Animal {
constructor(name) {
super(name, 'woof'); // call parent constructor
this.tricks = [];
}
learn(trick) { this.tricks.push(trick); }
speak() {
return `${super.speak()} and knows: ${this.tricks.join(', ')}`;
}
}
const d = new Dog('Bruno');
d.learn('sit');
d.speak(); // 'Bruno says woof and knows: sit'
d instanceof Dog; // true
d instanceof Animal; // true
ES Modules
Intermediate · 8 min read
// math.js — named exports
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export function mul(a, b) { return a * b; }
// user.js — default export
export default class User { ... }
// main.js — importing
import User from './user.js'; // default
import { add, PI } from './math.js'; // named
import { add as sum } from './math.js'; // aliased
import * as Math from './math.js'; // namespace
// Dynamic import (lazy loading)
const { add } = await import('./math.js');
// Re-exporting (barrel file: index.js)
export { add, mul } from './math.js';
export { default as User } from './user.js';
💡 Use <script type="module"> in HTML to enable ES modules in the browser. Modules are always in strict mode and have their own scope.
Error Handling
Intermediate · 8 min read
// try / catch / finally
try {
const data = JSON.parse(invalidJson);
} catch (e) {
if (e instanceof SyntaxError) {
console.error('Invalid JSON');
} else {
throw e; // re-throw unknown errors
}
} finally {
console.log('Always runs');
}
// Custom Error classes
class ApiError extends Error {
constructor(message, statusCode) {
super(message);
this.name = 'ApiError';
this.statusCode = statusCode;
}
}
throw new ApiError('Not Found', 404);
// Error types
new Error('Generic');
new TypeError('Wrong type');
new RangeError('Out of range');
new ReferenceError('Not defined');
new SyntaxError('Invalid syntax');
// Global unhandled rejection handler
window.addEventListener('unhandledrejection', (e) => {
console.error('Unhandled promise rejection:', e.reason);
e.preventDefault();
});
Regular Expressions
Advanced · 10 min read
// Create regex
const re1 = /hello/i; // literal, case-insensitive
const re2 = new RegExp('hello', 'i'); // dynamic
// Flags
// i — case insensitive
// g — global (find all)
// m — multiline (^ and $ match per line)
// s — dotAll (. matches newline)
// Methods
/\d+/.test('abc123'); // true
'hello'.match(/l+/g); // ['ll']
'hello'.replace(/l/g, 'r'); // 'herro'
'a,b,,c'.split(/,+/); // ['a','b','c']
// Common patterns
/^[\w.-]+@[\w.-]+\.\w{2,}$/ // email
/^\d{10}$/ // 10-digit phone
/^(?=.*[A-Z])(?=.*\d).{8,}$/ // password (1 upper + 1 digit + 8 chars)
/https?:\/\/[\w./?=#%-]+/g // URLs
// Named capture groups (ES2018)
const { groups: { year, month } } =
'2024-06-15'.match(/(?<year>\d{4})-(?<month>\d{2})/);
Generators & Iterators
Advanced · 10 min read
// Generator function — pausable with yield
function* counter(start = 0) {
while (true) {
yield start++;
}
}
const gen = counter(1);
gen.next(); // { value: 1, done: false }
gen.next(); // { value: 2, done: false }
// Finite generator
function* range(start, end, step = 1) {
for (let i = start; i < end; i += step) yield i;
}
[...range(0, 10, 2)]; // [0,2,4,6,8]
// Custom iterable
const iterable = {
[Symbol.iterator]: function*() {
yield 1; yield 2; yield 3;
}
};
for (const x of iterable) console.log(x); // 1, 2, 3
// Async generator
async function* streamData() {
const pages = [1, 2, 3];
for (const page of pages) {
yield await fetchPage(page);
}
}
for await (const chunk of streamData()) {
console.log(chunk);
}
Proxy & Reflect
Advanced · 10 min read
Proxy wraps an object and intercepts operations (get, set, delete). Reflect provides methods that mirror those interceptable operations.
// Validation proxy
const user = new Proxy({}, {
set(target, key, value) {
if (key === 'age' && typeof value !== 'number') {
throw new TypeError('age must be a number');
}
return Reflect.set(target, key, value);
}
});
user.name = 'Aftab'; // OK
user.age = '28'; // throws TypeError
// Logging proxy
const logged = new Proxy(api, {
get(target, key) {
console.log(`Accessing: ${key}`);
return Reflect.get(target, key);
}
});
// Default values proxy
function withDefaults(obj, defaults) {
return new Proxy(obj, {
get(target, key) {
return Reflect.get(target, key) ?? defaults[key];
}
});
}
JavaScript Design Patterns
Advanced · 12 min read
// 1. Singleton
class Config {
static #instance;
static getInstance() {
if (!Config.#instance) Config.#instance = new Config();
return Config.#instance;
}
}
// 2. Observer / Pub-Sub
class EventBus {
#listeners = {};
on(event, fn) { (this.#listeners[event] ??= []).push(fn); }
emit(event, data) { this.#listeners[event]?.forEach(fn => fn(data)); }
off(event, fn) { this.#listeners[event] = this.#listeners[event]?.filter(f => f !== fn); }
}
// 3. Factory
function createUser(role) {
const roles = { admin: AdminUser, guest: GuestUser };
return new roles[role]();
}
// 4. Strategy
const sorters = {
bubble: arr => { /* bubble sort */ },
quick: arr => { /* quick sort */ }
};
function sort(arr, strategy = 'quick') { return sorters[strategy](arr); }
// 5. Decorator (function wrapping)
function memoize(fn) {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = fn(...args);
cache.set(key, result);
return result;
};
}
const fastFib = memoize(n => n < 2 ? n : fastFib(n-1) + fastFib(n-2));