Advanced JavaScript Code Challenges – Build Core Features from Scratch
Level up your JavaScript skills with hands-on coding questions that simulate real-world scenarios. From building an LRU cache and custom Promise implementation to simulating async/await, deep cloning, and writing a debounce with maxWait — this guide is ideal for developers preparing for advanced technical interviews.
Hard
- 1.Implement LRU Cache
class LRUCache { constructor(limit) { this.cache = new Map(); this.limit = limit; } get(key) { if (!this.cache.has(key)) return -1; const value = this.cache.get(key); this.cache.delete(key); this.cache.set(key, value); // re-insert to make most recent return value; } put(key, value) { if (this.cache.has(key)) { this.cache.delete(key); } else if (this.cache.size >= this.limit) { const oldest = this.cache.keys().next().value; this.cache.delete(oldest); } this.cache.set(key, value); } } // Usage: const cache = new LRUCache(2); cache.put("a", 1); cache.put("b", 2); cache.get("a"); // returns 1 cache.put("c", 3); // evicts "b" console.log(cache.get("b")); // returns -1
- 2. Deep Clone without JSON
function deepClone(obj, hash = new WeakMap()) { if (obj === null || typeof obj !== "object") return obj; if (hash.has(obj)) return hash.get(obj); const clone = Array.isArray(obj) ? [] : {}; hash.set(obj, clone); for (let key in obj) { if (obj.hasOwnProperty(key)) { clone[key] = deepClone(obj[key], hash); } } return clone; }
- 3. Build a Promise from Scratch
class MyPromise { constructor(executor) { this.status = "pending"; this.value = undefined; this.reason = undefined; this.thenCallbacks = []; this.catchCallbacks = []; const resolve = (value) => { if (this.status === "pending") { this.status = "fulfilled"; this.value = value; this.thenCallbacks.forEach(cb => cb(value)); } }; const reject = (reason) => { if (this.status === "pending") { this.status = "rejected"; this.reason = reason; this.catchCallbacks.forEach(cb => cb(reason)); } }; try { executor(resolve, reject); } catch (err) { reject(err); } } then(cb) { if (this.status === "fulfilled") { cb(this.value); } else { this.thenCallbacks.push(cb); } return this; } catch(cb) { if (this.status === "rejected") { cb(this.reason); } else { this.catchCallbacks.push(cb); } return this; } }
- 4. Simulate async/await using generators
function runGenerator(genFn) { const iterator = genFn(); function handle(result) { if (result.done) return Promise.resolve(result.value); return Promise.resolve(result.value).then(res => handle(iterator.next(res))); } return handle(iterator.next()); } // Example usage function* fetchData() { const user = yield Promise.resolve("User: John"); console.log(user); const posts = yield Promise.resolve("Posts: 5"); console.log(posts); } runGenerator(fetchData);
- 5. Event Emitter
class EventEmitter { constructor() { this.events = {}; } on(event, listener) { if (!this.events[event]) this.events[event] = []; this.events[event].push(listener); } emit(event, ...args) { if (this.events[event]) { for (let fn of this.events[event]) fn(...args); } } off(event, listenerToRemove) { if (!this.events[event]) return; this.events[event] = this.events[event].filter(fn => fn !== listenerToRemove); } } // Usage const emitter = new EventEmitter(); const greet = (name) => console.log(`Hello, ${name}`); emitter.on("greet", greet); emitter.emit("greet", "Mahendran"); // Hello, Mahendran emitter.off("greet", greet);
- 6. Function Currying
function curry(fn) { return function curried(...args) { if (args.length >= fn.length) return fn(...args); return function (...next) { return curried(...args, ...next); }; }; } // Example function sum(a, b, c) { return a + b + c; } const curriedSum = curry(sum); console.log(curriedSum(1)(2)(3)); // 6
- 7. Custom Reduce
Array.prototype.myReduce = function (callback, initialValue) { let acc = initialValue !== undefined ? initialValue : this[0]; let start = initialValue !== undefined ? 0 : 1; for (let i = start; i < this.length; i++) { acc = callback(acc, this[i], i, this); } return acc; };
- 8. Debounce with maxWait
function debounce(fn, wait, maxWait) { let timer, startTime; return function (...args) { const now = Date.now(); if (!startTime) startTime = now; clearTimeout(timer); if (now - startTime >= maxWait) { fn.apply(this, args); startTime = null; } else { timer = setTimeout(() => { fn.apply(this, args); startTime = null; }, wait); } }; }
- 9.Basic DOM Diff Algorithm
function diff(oldNode, newNode) { const changes = []; function walk(o, n, path = '') { if (!o && n) { changes.push(`Add ${path}: ${JSON.stringify(n)}`); } else if (o && !n) { changes.push(`Remove ${path}`); } else if (typeof o !== typeof n) { changes.push(`Change ${path}: ${JSON.stringify(o)} => ${JSON.stringify(n)}`); } else if (typeof o === 'object') { const keys = new Set([...Object.keys(o), ...Object.keys(n)]); keys.forEach(k => walk(o[k], n[k], path ? `${path}.${k}` : k)); } else if (o !== n) { changes.push(`Change ${path}: ${o} => ${n}`); } } walk(oldNode, newNode); return changes; }
- 10. Async Retry with Exponential Backoff
async function retry(fn, retries = 3, delay = 1000) { try { return await fn(); } catch (err) { if (retries === 0) throw err; await new Promise(res => setTimeout(res, delay)); return retry(fn, retries - 1, delay * 2); } }
- 11. Implement custom map()
Array.prototype.myMap = function (cb) { let result = []; for (let i = 0; i < this.length; i++) { result.push(cb(this[i], i, this)); } return result; };
- 12. Convert nested object to flat
function flattenObj(obj, prefix = '', res = {}) { for (let key in obj) { let path = prefix ? `${prefix}.${key}` : key; typeof obj[key] === 'object' && obj[key] !== null ? flattenObj(obj[key], path, res) : res[path] = obj[key]; } return res; }
- 13. Check deep equality
function isEqual(a, b) { return JSON.stringify(a) === JSON.stringify(b); }
- 14. Find longest word in sentence
str.split(' ').reduce((a, b) => a.length > b.length ? a : b);
- 15. Sum of even numbers in array
arr.filter(n => n % 2 === 0).reduce((a, b) => a + b, 0);
- 16. Find all pairs that sum to a target
function pairSum(arr, target) { let seen = new Set(), pairs = []; for (let num of arr) { let comp = target - num; if (seen.has(comp)) pairs.push([num, comp]); seen.add(num); } return pairs; }
- 17. Count character frequency
[...str].reduce((acc, ch) => ((acc[ch] = acc[ch] + 1 || 1), acc), {});
- 18. Rotate array by K
function rotate(arr, k) { k = k % arr.length; return [...arr.slice(-k), ...arr.slice(0, -k)]; }
- 19. Convert Roman numeral to integer
function romanToInt(s) { const map = {I:1,V:5,X:10,L:50,C:100,D:500,M:1000}; let total = 0; for (let i = 0; i < s.length; i++) { const val = map[s[i]]; const next = map[s[i+1]]; total += val < next ? -val : val; } return total; }
- 20. Get second largest number
const secondLargest = [...new Set(arr)].sort((a, b) => b - a)[1];