Back to Exercises
Functions & Patterns
20 Exercises Available
Reusable functions, default params, wrappers — develop a clean code mindset.
1.Hard
Debounce (real-world)
Create a function debounce(fn, delay) that calls fn only when no new call occurs within delay ms after last call. Use-case: search input.
Sample Output:
const debouncedSearch = debounce((query) => console.log(query), 300);
debouncedSearch("h"); debouncedSearch("he"); debouncedSearch("hel");
// After 300ms: only "hel" loggedView Solution
2.Hard
Memoize (simple)
Create a function memoize(fn) that returns cached result for same args. Assume args are JSON-serializable.
Sample Output:
const memoizedFn = memoize((a, b) => a + b); memoizedFn(5, 10) => 15 (computed) memoizedFn(5, 10) => 15 (cached)
View Solution
3.Medium
Safe Execute (try/catch wrapper)
Create a function safe(fn, fallback) that runs fn in try/catch. Return fallback if error occurs.
Sample Output:
safe(() => JSON.parse('{"a":1}')) => {a: 1}
safe(() => JSON.parse('invalid')) => nullView Solution
4.Medium
Once (run only once)
Create a function once(fn) that executes fn only the first time, then returns the same result.
Sample Output:
const onceFn = once(() => console.log("init"));
onceFn(); onceFn(); onceFn();
// Output: "init" (only once)View Solution
5.Medium
Pipe (left-to-right)
Create a function pipe(...fns) that applies value left-to-right.
Sample Output:
pipe((x) => x * 2, (x) => x + 5, (x) => x * 3)(10) => 75 // Steps: 10*2=20, 20+5=25, 25*3=75
View Solution
6.Hard
Curry Function (partial application)
Create a function `curry(fn)` that curries a function. Example: curry((a, b, c) => a + b + c) → (a) => (b) => (c) => a + b + c
Sample Output:
const add = curry((a, b, c) => a + b + c); add(1)(2)(3) => 6 add(1, 2)(3) => 6
View Solution
7.Medium
Compose Function (right to left)
Create a function `compose(...fns)` that composes functions (right to left). Example: compose(f, g, h)(x) → f(g(h(x)))
Sample Output:
compose((x) => x * 2, (x) => x + 1)(5) => 12 // Steps: 5+1=6, 6*2=12
View Solution
8.Hard
Bind Function (custom implementation)
Create a function `bind(fn, context, ...args)` that binds function with context and partial args.
Sample Output:
const obj = {x: 10};
const bound = bind(function(y) { return this.x + y; }, obj, 5);
bound(3) => 18View Solution
9.Medium
Partial Application Helper
Create a function `partial(fn, ...args)` that binds function with partial args.
Sample Output:
const add = (a, b, c) => a + b + c; const add5 = partial(add, 5); add5(10, 15) => 30
View Solution
10.Hard
Trampoline (recursion optimization)
Create a function `trampoline(fn)` that optimizes recursive function (prevent stack overflow).
Sample Output:
const factorial = trampoline((n, acc = 1) => n <= 1 ? acc : () => factorial(n - 1, n * acc)); factorial(10000) => (large number, no stack overflow)
View Solution
11.Medium
Lazy Evaluation (generator)
Create a function `lazyRange(start, end)` that returns a generator function that lazily generates values.
Sample Output:
const range = lazyRange(1, 5); range.next().value => 1 range.next().value => 2
View Solution
12.Easy
Higher-Order Function: Map Implementation
Create a function `myMap(arr, fn)` that is a custom implementation of array.map().
Sample Output:
myMap([1, 2, 3], x => x * 2) => [2, 4, 6] myMap([1, 2, 3], (x, i) => x + i) => [1, 3, 5]
View Solution
13.Easy
Higher-Order Function: Filter Implementation
Create a function `myFilter(arr, fn)` that is a custom implementation of array.filter().
Sample Output:
myFilter([1, 2, 3, 4], x => x % 2 === 0) => [2, 4] myFilter([1, 2, 3], x => x > 1) => [2, 3]
View Solution
14.Medium
Higher-Order Function: Reduce Implementation
Create a function `myReduce(arr, fn, initial)` that is a custom implementation of array.reduce().
Sample Output:
myReduce([1, 2, 3], (acc, x) => acc + x, 0) => 6 myReduce([1, 2, 3], (acc, x) => acc + x) => 6
View Solution
15.Hard
Function Overloading (simulate)
Create a function `overload(...handlers)` that executes different handlers based on different argument types.
Sample Output:
const fn = overload(
{match: (x) => typeof x === "string", fn: (x) => x.toUpperCase()},
{match: (x) => typeof x === "number", fn: (x) => x * 2}
);
fn("hello") => "HELLO"
fn(5) => 10View Solution
16.Medium
Function Cache (with key generator)
Create a function `cache(fn, keyGen)` that caches function results with custom key generator.
Sample Output:
const expensive = cache((n) => n * 2, (n) => `num_${n}`);
expensive(5) => 10 (computed)
expensive(5) => 10 (cached)View Solution
17.Easy
Function Timer (execution time)
Create a function `withTimer(fn)` that wraps function and measures execution time.
Sample Output:
const timed = withTimer((n) => n * 2); timed(5) => 10 // Console: "Execution time: 0.1ms"
View Solution
18.Medium
Function Retry Wrapper
Create a function `withRetry(fn, maxAttempts)` that retries function on failure.
Sample Output:
const retried = withRetry(async () => fetchAPI(), 3); await retried() => (retries up to 3 times on failure)
View Solution
19.Easy
Function Logger (call logging)
Create a function `withLogger(fn, label)` that logs function calls.
Sample Output:
const logged = withLogger((x) => x * 2, "Double"); logged(5) => 10 // Console: "[Double] Called with: [5]" // Console: "[Double] Returned: 10"
View Solution
20.Medium
Function Validator (input validation)
Create a function `withValidation(fn, validator)` that validates function inputs before execution.
Sample Output:
const validated = withValidation((x) => x * 2, (x) => typeof x === "number");
validated(5) => 10
validated("5") => throws Error("Validation failed")View Solution