Loading...
Loading...
Proven solutions to common problems. Patterns that professional developers use daily.
Module 10 · Browser Internals & Best Practices
Production JavaScript requires more than syntax. The event loop, rendering pipeline, bundlers, debugging techniques, performance optimization, design patterns, testing, and security practices separate hobby scripts from professional software.
Learn Design Patterns in JavaScript — covering Singleton, Observer, Factory, Strategy with interactive visual examples and step-by-step explanations.
Writing JavaScript that works in a tutorial is different from writing JavaScript that ships to production. The event loop explains why setTimeout(0) does not run immediately. Performance profiling finds bottlenecks before users do.
This module covers the internals and best practices that separate hobby scripts from professional software: debugging, bundlers, design patterns, testing strategies, and security fundamentals every developer should know.
Understanding design patterns is essential for every JavaScript developer. It shows up in frontend UI code, backend APIs, and framework internals — and getting it wrong leads to bugs that are hard to trace. This chapter builds intuition with visuals so the behavior sticks.
One instance, shared everywhere. Global state done right.
// Singleton — only ONE instance ever exists: class Database { static #instance = null; constructor() { if (Database.#instance) { return Database.#instance; // return existing } this.connection = createConnection(); Database.#instance = this; } query(sql) { return this.connection.execute(sql); } } const db1 = new Database(); const db2 = new Database(); console.log(db1 === db2); // true — same instance! // Module pattern (simpler in ES modules): // Each module is already a singleton! // config.js: const config = { apiUrl: "https://api.example.com", timeout: 5000, }; export default config; // Every import gets the SAME object. // Practical use — app-wide store: let state = { user: null, theme: "dark" }; export function getState() { return state; } export function setState(patch) { state = { ...state, ...patch }; }
When something changes, notify everyone who cares.
// Observer — one-to-many dependency: // When subject changes, all observers are notified. class EventEmitter { #listeners = new Map(); on(event, callback) { if (!this.#listeners.has(event)) { this.#listeners.set(event, []); } this.#listeners.get(event).push(callback); // Return unsubscribe function: return () => this.off(event, callback); } off(event, callback) { const list = this.#listeners.get(event); if (list) { this.#listeners.set(event, list.filter(cb => cb !== callback)); } } emit(event, data) { const list = this.#listeners.get(event) || []; list.forEach(callback => callback(data)); } } // Usage: const emitter = new EventEmitter(); const unsub = emitter.on("userLogin", (user) => { console.log(`${user.name} logged in!`); }); emitter.emit("userLogin", { name: "Alice" }); // "Alice logged in!" unsub(); // stop listening
Create objects without specifying exact classes.
// Factory — creation logic in one place: function createNotification(type, message) { const base = { id: crypto.randomUUID(), message, timestamp: Date.now() }; switch (type) { case "success": return { ...base, icon: "✓", color: "green", duration: 3000 }; case "error": return { ...base, icon: "✕", color: "red", duration: 0 }; // stays case "warning": return { ...base, icon: "⚠", color: "yellow", duration: 5000 }; default: return { ...base, icon: "ℹ", color: "blue", duration: 4000 }; } } // Caller doesn't know internal structure: const n1 = createNotification("success", "Saved!"); const n2 = createNotification("error", "Connection failed"); // Factory with registration (extensible): const validators = {}; function registerValidator(type, fn) { validators[type] = fn; } function validate(type, value) { const validator = validators[type]; if (!validator) throw new Error(`Unknown type: ${type}`); return validator(value); } registerValidator("email", v => v.includes("@")); registerValidator("phone", v => /^\d{10}$/.test(v)); validate("email", "a@b.com"); // true
Swap algorithms at runtime without changing calling code.
// Strategy — interchangeable behaviors: const sortStrategies = { byName: (a, b) => a.name.localeCompare(b.name), byDate: (a, b) => new Date(b.date) - new Date(a.date), byPrice: (a, b) => a.price - b.price, byRating: (a, b) => b.rating - a.rating, }; function sortProducts(products, strategy = "byName") { return [...products].sort(sortStrategies[strategy]); } // Swap sorting without changing function: sortProducts(items, "byPrice"); sortProducts(items, "byRating"); // Auth strategy: const authStrategies = { jwt: { authenticate(req) { return verifyJWT(req.headers.authorization); }, }, apiKey: { authenticate(req) { return checkApiKey(req.headers["x-api-key"]); }, }, session: { authenticate(req) { return getSession(req.cookies.sid); }, }, }; function authenticate(req, strategy) { return authStrategies[strategy].authenticate(req); } // Easy to add new strategies without modifying existing code!
Decouple publishers from subscribers completely.
// Pub/Sub — publishers don't know about subscribers: // Unlike Observer, there's a message broker in between. class MessageBus { #channels = new Map(); subscribe(channel, handler) { if (!this.#channels.has(channel)) { this.#channels.set(channel, new Set()); } this.#channels.get(channel).add(handler); return () => this.#channels.get(channel).delete(handler); } publish(channel, data) { const handlers = this.#channels.get(channel); if (handlers) handlers.forEach(h => h(data)); } } const bus = new MessageBus(); // Components subscribe independently: bus.subscribe("cart:updated", (cart) => { updateCartIcon(cart.count); }); bus.subscribe("cart:updated", (cart) => { updateTotal(cart.total); }); // Any component can publish — no direct coupling: function addToCart(product) { cart.items.push(product); bus.publish("cart:updated", { count: cart.items.length, total: cart.items.reduce((s, i) => s + i.price, 0), }); } // Real-world: Redux, Zustand, and React Context // all use variations of Pub/Sub under the hood.
Common questions about design patterns.