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" logged
View 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')) => null
View 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) => 18
View 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) => 10
View 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