JavaScript Problems
Master advanced JavaScript concepts with real interview problems and polyfills.
Master advanced JavaScript concepts with real interview problems and polyfills.
40 of 40 problems
Implement memoize(fn, resolver?) to cache results of pure functions. Use resolver to compute the cache key, or default to the first argument when it is a primitive. Preserve this when calling fn so methods still work.
Implement once(fn) so that fn is called only on the first invocation and its first return value is reused for all subsequent calls. Preserve this and arguments. The returned wrapper should behave like a normal function otherwise.
Implement debounce(fn, delay) that delays invoking fn until delay ms have passed since the last call. Only the last call in a burst should trigger fn. The debounced function should also expose a .cancel() method.
Implement throttle(fn, interval) that ensures fn is called at most once every interval ms, firing immediately on the first call and once more at the end of the window with the latest args (trailing call).
Re‑implement Function.prototype.myCall and Function.prototype.myBind (no new handling) so they behave like call and bind, correctly binding this and arguments when used on regular functions.
Implement compose(...fns) so that compose(f, g, h)(x) computes f(g(h(x))). Handle the empty case by returning an identity function that simply returns its input.
Implement promiseAll(iterable) that takes values/promises and returns a promise that resolves with all results in order, or rejects immediately on the first failure. Non‑promise values should be treated as already resolved.
Design a minimal EventEmitter with on, off, emit and once APIs so that handlers can subscribe to and emit named events in registration order. Handlers should run in the order they were registered.
Implement flatten(input) that recursively flattens an arbitrarily nested array of primitives into a new one‑dimensional array without mutating the original input.
Implement deepClone(value) that deeply clones plain objects, arrays and Date instances without sharing references. You can ignore functions, Maps/Sets, DOM nodes and circular references for this version.
Implement `allSettled(promises)` similar to `Promise.allSettled`. Input: array/iterable of values or promises. Output: a promise that always resolves with an array of objects: `{ status: 'fulfilled', value }` or `{ status: 'rejected', reason }`.
Implement `pipe(...fns)` which is the left‑to‑right version of `compose`. `pipe(f, g, h)(x)` should compute `h(g(f(x)))`. If no functions are provided, return an identity function.
Implement a `nextTick(fn)` helper that schedules `fn` to run as a microtask after the current call stack, but before the next macrotask (like `setTimeout`). Returns a promise that resolves after `fn` has run.
Design and implement an `LRUCache` class with `constructor(capacity)`, `get(key)` that returns the value or `undefined` and marks the entry as most recently used, and `set(key, value)` that inserts/updates a value and evicts the least recently used key if capacity is exceeded.
Implement a function `deepEqual(a, b)` that returns `true` if `a` and `b` are deeply equal. Handles primitives, arrays, plain objects, and Date instances. You can ignore Maps, Sets, functions, and cycles for this version.
Implement a function `curry(fn)` that transforms a function of N arguments into a chain of N (or fewer) function calls. You can call the curried function with any number of arguments each time. Once the total number of supplied arguments reaches `fn.length`, call `fn` and return the result.
Implement `retry(fn, options)` where `fn` is an async function. Options can have `retries` (max number of retries, default 3), `delay` (initial delay in ms, default 100), and `factor` (backoff multiplier, default 2). If all retries fail, reject with the last error.
Implement `withTimeout(promise, ms)` that returns a new promise. If `promise` settles (resolves or rejects) before `ms`, forward that result. Otherwise, reject with a `TimeoutError`.
Implement `createBatcher(fn)` where `fn` expects an array of items and returns an array of results. `createBatcher(fn)` returns a function `batch(item)` that queues up items called in the same event loop tick and calls `fn` once with all queued items.
Implement `promisify(fn)` where `fn` is a Node‑style function with a callback as the last argument `(err, result)`. `promisify(fn)` should return a new function that takes the same arguments (except the callback) and returns a promise.
Implement `groupBy(array, keyFn)` that groups array elements into an object. `keyFn(element, index)` returns the key for grouping. Returns an object where keys are the group keys and values are arrays of elements in that group.
Implement `createReducer(initialState, handlers)` that returns a reducer function. `handlers` is an object mapping action types to reducer functions. The returned reducer takes `(state, action)` and calls the appropriate handler or returns the current state.
Implement `createMiddleware(...middlewares)` that returns a function that executes middleware in sequence. Each middleware is a function `(req, res, next)`. `next()` calls the next middleware. If a middleware doesn't call `next()`, the chain stops.
Implement `createObservable(initialValue)` that returns an observable object. `observable.value` gets/sets the current value. `observable.subscribe(fn)` subscribes to value changes and returns an unsubscribe function. When `value` changes, all subscribers are notified with `(newValue, oldValue)`.
Implement `delay(fn, ms)` that returns a function that, when called, executes `fn` after `ms` milliseconds.
Implement `partition(array, predicate)` that splits an array into two arrays. First array contains elements where `predicate(element, index)` returns truthy. Second array contains elements where `predicate` returns falsy.
Implement `createRateLimiter(maxCalls, windowMs)` that returns a function wrapper. The wrapper allows at most `maxCalls` invocations within `windowMs` milliseconds. If the limit is exceeded, the call throws an error. After `windowMs`, the counter resets.
Implement `chunk(array, size)` that splits an array into chunks of the given size. Returns an array of arrays. The last chunk may be smaller than `size` if the array length isn't divisible.
Implement `flatMap(array, fn)` that behaves like `Array.prototype.flatMap`. Maps each element using `fn(element, index, array)` and flattens the result by one level. Returns a new array.
Implement `race(iterable)` that behaves like `Promise.race`. Takes an array/iterable of values or promises. Returns a promise that settles (resolves or rejects) with the result of the first promise that settles.
What is the output of this code? Explain why: `for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100); }`
Implement `createProxy(target, handlers)` that returns a Proxy with `get` trap that logs property access and `set` trap that logs property assignment. Return the proxied object.
Implement `uncurry(fn)` that takes a curried function and returns a function that accepts all arguments at once.
Implement `tap(fn)` that returns a function which takes a value, calls `fn(value)`, then returns the original value. Useful for debugging/logging in function pipelines.
What is the output of this code? Explain hoisting and Temporal Dead Zone: `console.log(a); console.log(b); var a = 1; let b = 2;`
Implement `createLazy(fn)` that returns a lazy function. The function doesn't execute until its result is accessed. The result is cached after first access. Useful for expensive computations.
What is the output of this code? Explain the `this` binding: `const obj = { name: 'Alice', greet: function() { console.log(this.name); }, greetArrow: () => { console.log(this.name); } }; obj.greet(); obj.greetArrow(); const fn = obj.greet; fn();`