// Pure
function add(a, b) { return a + b; }
// Impure — depends on and mutates external state
let total = 0;
function addToTotal(n) { total += n; }
Topics
37
ArrayBuffer, TypedArrays & Binary Data
Arrays & Array Methods
Async Iterators & Streams
Browser Storage & Web APIs
Classes & Class Syntax
Date, Time & Internationalization (Intl API)
Debugging, Testing & Tooling
Design Patterns in JavaScript
Destructuring, Spread & Rest
DOM & Events
Error Handling
ES Modules
Event Loop & Concurrency
Functional Programming
Iterators & Generators
JSON & Data Serialization
Map, Set, WeakMap & WeakSet
Memory Management & Garbage Collection
Networking: Fetch, XHR, WebSockets & CORS
Numbers, Math & BigInt
Objects, Property Descriptors & Immutability
Optional Chaining & Nullish Coalescing
Package Management, Bundlers & Transpilation (npm, Webpack/Vite, Babel)
Performance Optimization: Debouncing, Throttling & Memoization
Promises & async/await
Prototypes & Inheritance
Proxy & Reflect
Regular Expressions
Scope, Hoisting & Closures
Security: XSS, CSRF & Content Security Policy
Service Workers & Progressive Web Apps
Strings & Template Literals
Symbols & Well-Known Symbols
this & Binding
Types & Coercion
Web Components & Custom Elements
Web Workers & Multithreading
Functional Programming
10 questions found
A pure function always returns the same output for the same input and produces no observable side effects (no mutating external state, no I/O), which makes it predictable, testable, and easy to reason about in isolation.
Real-world example
Preferring pure calculation functions in a reducer or utility layer for predictable, easily-testable behavior.
Error Handling
Immutability means not modifying data after it's created — instead, you produce new data structures with the desired changes. This avoids bugs from shared mutable state and makes it easier to track how and when data changes.
// Mutating (avoid)
const arr = [1,2,3];
arr.push(4);
// Immutable (preferred)
const arr2 = [...arr, 4];
Real-world example
Avoiding accidental shared-state bugs in React, where mutating state directly can cause missed re-renders.
Destructuring
Spread & Rest
A higher-order function either accepts one or more functions as arguments, returns a function, or both — array methods like map, filter, and reduce are common built-in examples.
function multiplyBy(factor) {
return (n) => n * factor; // returns a function
}
const double = multiplyBy(2);
double(5); // 10
Real-world example
Building a configurable validation function generator, like requireMinLength(5).
Closures
Composition combines multiple small functions into one, where the output of each becomes the input to the next — typically implemented with a compose() or pipe() helper that reduces over an array of functions.
const pipe = (...fns) => (x) => fns.reduce((acc, fn) => fn(acc), x);
const addOne = n => n + 1;
const double = n => n * 2;
const transform = pipe(addOne, double);
transform(3); // (3+1)*2 = 8
Real-world example
Building a data-processing pipeline that trims, validates, then formats user input in clearly separated steps.
Destructuring
Spread & Rest
Currying transforms a function taking multiple arguments into a sequence of functions each taking a single argument, allowing you to partially apply some arguments early and reuse the resulting specialized function later.
const curriedAdd = (a) => (b) => (c) => a + b + c;
const addFive = curriedAdd(5);
addFive(2)(3); // 10
Real-world example
Creating a reusable, pre-configured validator like isLongerThan(8) from a generic two-argument comparison function.
Closures
Why are recursion and immutable data often used together in functional style, instead of loops with mutable counters?
IntermediateRecursion naturally avoids mutable loop counters and accumulator variables by passing updated state as arguments to each recursive call, keeping each step's data immutable and self-contained — matching the broader functional preference for avoiding shared mutable state.
function sum(arr, acc = 0) {
if (arr.length === 0) return acc;
const [first, ...rest] = arr;
return sum(rest, acc + first); // no mutable counter
}
sum([1,2,3]); // 6
Real-world example
Processing a linked-list-like or tree-like data structure where a recursive, immutable approach mirrors its shape naturally.
Error Handling
What does 'referential transparency' mean, and how does it enable optimizations like memoization?
AdvancedAn expression is referentially transparent if it can be replaced with its computed value without changing the program's behavior — true only for pure functions with no side effects. This property is exactly what makes memoization (caching results by input) safe: you can trust that the same input always deserves the same cached output.
function memoize(fn) {
const cache = new Map();
return (arg) => {
if (cache.has(arg)) return cache.get(arg);
const result = fn(arg); // safe to cache only if fn is pure
cache.set(arg, result);
return result;
};
}
Real-world example
Memoizing an expensive pure calculation, like a Fibonacci function or a complex pricing formula.
Map
Set
WeakMap & WeakSet
How do you implement a debounce function using closures, and how is it a functional programming technique?
Advanceddebounce() returns a new function that wraps a closure over a timer variable, delaying the original function's execution until a pause in calls occurs — it's a higher-order function that takes a function and returns an enhanced function, a core FP pattern.
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}
const debouncedSearch = debounce(runSearch, 300);
Real-world example
Delaying an API search request until the user stops typing for 300ms, instead of firing on every keystroke.
Performance Optimization: Debouncing
Throttling & Memoization
What are functors and monads, at a practical level, and does JavaScript have native support for them?
AdvancedA functor is any structure with a .map() method that applies a function to its wrapped value while keeping the wrapper (Array and Promise both qualify). A monad additionally has a way to 'flatten' nested wrappers (like Promise's automatic chaining, or Array's flatMap). JavaScript doesn't enforce these as formal types, but Array and Promise both behave like a functor/monad in practice.
// Array as a functor
[1,2,3].map(n => n * 2); // [2,4,6]
// Promise behaves monad-like: chained then() auto-flattens nested promises
Promise.resolve(1).then(n => Promise.resolve(n + 1)).then(console.log); // 2
Real-world example
Recognizing that chaining .then() on Promises already gives you monad-like flattening for free, without needing a library.
Iterators & Generators
Use spread syntax (or structuredClone/immutable libraries like Immer) to create new objects/arrays at each level being changed, copying siblings shallowly while replacing only the path that changed — avoiding direct mutation of nested structures.
const state = { user: { profile: { age: 30 } } };
const updated = {
...state,
user: {
...state.user,
profile: { ...state.user.profile, age: 31 }
}
};
Real-world example
Updating a single deeply nested field in Redux or React state without mutating the original state object.
Destructuring
Spread & Rest