Master JavaScript interviews with this comprehensive collection of 60 hand-picked coding problems, complete with solutions, time complexity analysis, and expert interview tips.
Are you preparing for a JavaScript developer interview and feeling overwhelmed by the endless list of potential coding questions? You're not alone. Whether you're applying for a frontend developer, full-stack engineer, or Node.js position, mastering JavaScript interview questions is crucial for landing your dream job.
This ultimate JavaScript coding interview cheat sheet is designed for developers who want to:
✅ Quickly review the most commonly asked JavaScript coding problems
✅ Understand time complexity and optimization techniques
✅ Learn what to say during technical interviews to impress interviewers
✅ Practice essential patterns in strings, arrays, algorithms, async/await, and more
Unlike typical coding question lists, each problem in this guide includes:
- Clean, production-ready code using modern ES6+ syntax
- Interview tips - exactly what to explain during your interview
- Time and space complexity analysis for every solution
- Real-world applications so you understand when to use each pattern
- Junior developers preparing for their first technical interview
- Mid-level engineers brushing up on fundamentals
- Career switchers transitioning into web development
- Self-taught programmers without a CS degree
This comprehensive guide covers 60 JavaScript interview problems across 8 categories:
🔤 String Manipulation - Reverse, palindrome, anagram detection
📊 Array Operations - Two sum, rotation, flattening, chunking
🧮 Number Algorithms - Fibonacci, prime numbers, factorials
🎯 Object Handling - Deep clone, merge, nested access
⚡ Async/Promises - Debounce, throttle, retry logic
🔍 Classic Algorithms - Binary search, sorting, valid parentheses
🎨 Practical Utilities - UUID generation, query parsers, formatters
🏆 Advanced Patterns - Memoization, one-liners, performance optimization
Each solution is optimized for readability and interview performance. We prioritize code that's easy to explain under pressure while demonstrating your understanding of JavaScript fundamentals.
- Read through each category to familiarize yourself with common patterns
- Practice explaining the solutions out loud as if in an interview
- Focus on time complexity - interviewers love candidates who discuss Big O
- Memorize the "interview tips" - these are gold for technical discussions
- Try solving problems before looking at solutions to test your knowledge
JavaScript interview questions, coding interview preparation, frontend developer interview, JavaScript algorithms, web developer coding test, technical interview questions, JavaScript programming challenges, ES6 interview questions, coding patterns JavaScript, algorithm interview prep, JavaScript developer jobs 2025
const reverseString = str => [...str].reverse().join('');
console.log(reverseString("hello")); // "olleh"Interview tip: "Use spread/reverse/join for O(n) time complexity."
const isPalindrome = str => str === [...str].reverse().join('');
console.log(isPalindrome("racecar")); // true
console.log(isPalindrome("hello")); // falseInterview tip: "Check if string reads same forwards and backwards."
const countVowels = str => (str.match(/[aeiou]/gi) || []).length;
console.log(countVowels("hello world")); // 3Interview tip: "Use regex with match, handle null case with || []."
const capitalize = str => str.charAt(0).toUpperCase() + str.slice(1);
console.log(capitalize("hello")); // "Hello"Interview tip: "Use charAt(0) and slice(1) for clean solution."
const titleCase = str => str.split(' ').map(word =>
word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
).join(' ');
console.log(titleCase("hello world")); // "Hello World"Interview tip: "Split, map each word, capitalize first letter, join back."
const removeDuplicates = str => [...new Set(str)].join('');
console.log(removeDuplicates("hello")); // "helo"Interview tip: "Use Set for O(n) deduplication, spread back to array."
const longestWord = str => str.split(' ').reduce((longest, word) =>
word.length > longest.length ? word : longest, ''
);
console.log(longestWord("The quick brown fox")); // "quick"Interview tip: "Split and reduce to find maximum length word."
const isAnagram = (str1, str2) => {
const normalize = str => str.toLowerCase().split('').sort().join('');
return normalize(str1) === normalize(str2);
};
console.log(isAnagram("listen", "silent")); // trueInterview tip: "Sort both strings and compare. O(n log n) time."
const removeDuplicates = arr => [...new Set(arr)];
console.log(removeDuplicates([1, 2, 2, 3, 4, 4])); // [1, 2, 3, 4]Interview tip: "Set automatically removes duplicates, O(n) time."
const findMax = arr => Math.max(...arr);
console.log(findMax([1, 5, 3, 9, 2])); // 9Interview tip: "Use Math.max with spread operator for simplicity."
const sum = arr => arr.reduce((acc, num) => acc + num, 0);
console.log(sum([1, 2, 3, 4])); // 10Interview tip: "Reduce is perfect for accumulation, start with 0."
const flatten = arr => arr.flat(Infinity);
console.log(flatten([1, [2, [3, [4]]]])); // [1, 2, 3, 4]
// Recursive approach
const flattenRecursive = arr => arr.reduce((acc, val) =>
Array.isArray(val) ? acc.concat(flattenRecursive(val)) : acc.concat(val), []
);Interview tip: "Use flat(Infinity) or recursive reduce. Explain both."
const chunk = (arr, size) => {
const result = [];
for (let i = 0; i < arr.length; i += size) {
result.push(arr.slice(i, i + size));
}
return result;
};
console.log(chunk([1, 2, 3, 4, 5], 2)); // [[1, 2], [3, 4], [5]]Interview tip: "Slice array in chunks using loop. O(n) time."
const findMissing = arr => {
const n = arr.length + 1;
const expectedSum = (n * (n + 1)) / 2;
const actualSum = arr.reduce((a, b) => a + b, 0);
return expectedSum - actualSum;
};
console.log(findMissing([1, 2, 4, 5])); // 3Interview tip: "Use sum formula n(n+1)/2, compare with actual sum."
const rotate = (arr, k) => {
k = k % arr.length;
return [...arr.slice(-k), ...arr.slice(0, -k)];
};
console.log(rotate([1, 2, 3, 4, 5], 2)); // [4, 5, 1, 2, 3]Interview tip: "Slice and concatenate. Handle k > length with modulo."
const twoSum = (arr, target) => {
const map = new Map();
for (let i = 0; i < arr.length; i++) {
const complement = target - arr[i];
if (map.has(complement)) return [map.get(complement), i];
map.set(arr[i], i);
}
return null;
};
console.log(twoSum([2, 7, 11, 15], 9)); // [0, 1]Interview tip: "Use Map for O(n) solution. Store complement lookup."
const moveZeros = arr => {
const nonZeros = arr.filter(x => x !== 0);
const zeros = arr.filter(x => x === 0);
return [...nonZeros, ...zeros];
};
console.log(moveZeros([0, 1, 0, 3, 12])); // [1, 3, 12, 0, 0]Interview tip: "Filter non-zeros, then zeros, concatenate."
const intersection = (arr1, arr2) => [...new Set(arr1)].filter(x => arr2.includes(x));
console.log(intersection([1, 2, 3], [2, 3, 4])); // [2, 3]Interview tip: "Filter first array checking if item exists in second."
const fibonacci = n => {
if (n <= 1) return n;
let a = 0, b = 1;
for (let i = 2; i <= n; i++) {
[a, b] = [b, a + b];
}
return b;
};
console.log(fibonacci(7)); // 13Interview tip: "Iterative approach is O(n) time, O(1) space. Better than recursive."
const isPrime = num => {
if (num <= 1) return false;
for (let i = 2; i <= Math.sqrt(num); i++) {
if (num % i === 0) return false;
}
return true;
};
console.log(isPrime(17)); // trueInterview tip: "Check divisibility up to sqrt(n) for O(√n) time."
const factorial = n => n <= 1 ? 1 : n * factorial(n - 1);
console.log(factorial(5)); // 120
// Iterative
const factorialIterative = n => {
let result = 1;
for (let i = 2; i <= n; i++) result *= i;
return result;
};Interview tip: "Know both recursive and iterative. Mention tail recursion optimization."
const reverseNumber = num => parseInt([...String(Math.abs(num))].reverse().join('')) * Math.sign(num);
console.log(reverseNumber(12345)); // 54321
console.log(reverseNumber(-123)); // -321Interview tip: "Convert to string, reverse, handle negative with Math.sign."
const countDigits = num => String(Math.abs(num)).length;
console.log(countDigits(12345)); // 5Interview tip: "Convert to string and get length. Handle negatives."
const deepClone = obj => JSON.parse(JSON.stringify(obj));
console.log(deepClone({a: 1, b: {c: 2}})); // {a: 1, b: {c: 2}}
// Better with structuredClone
const deepClone2 = obj => structuredClone(obj);Interview tip: "JSON method works but loses functions. structuredClone is modern."
const merge = (obj1, obj2) => ({...obj1, ...obj2});
console.log(merge({a: 1}, {b: 2})); // {a: 1, b: 2}
// Deep merge
const deepMerge = (obj1, obj2) => {
const result = {...obj1};
for (let key in obj2) {
if (typeof obj2[key] === 'object' && !Array.isArray(obj2[key])) {
result[key] = deepMerge(result[key] || {}, obj2[key]);
} else {
result[key] = obj2[key];
}
}
return result;
};Interview tip: "Spread for shallow, recursive for deep merge."
const groupBy = (arr, key) => arr.reduce((acc, obj) => {
const group = obj[key];
acc[group] = acc[group] || [];
acc[group].push(obj);
return acc;
}, {});
const data = [{type: 'fruit', name: 'apple'}, {type: 'fruit', name: 'banana'}];
console.log(groupBy(data, 'type')); // {fruit: [{...}, {...}]}Interview tip: "Reduce with object accumulator. Create arrays on first encounter."
const getNestedProperty = (obj, path) => path.split('.').reduce((acc, key) => acc?.[key], obj);
console.log(getNestedProperty({a: {b: {c: 42}}}, 'a.b.c')); // 42Interview tip: "Split path, reduce with optional chaining for safety."
const isEqual = (obj1, obj2) => JSON.stringify(obj1) === JSON.stringify(obj2);
console.log(isEqual({a: 1}, {a: 1})); // trueInterview tip: "JSON stringify works for simple cases. Discuss deep comparison."
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
// Usage
await delay(1000);
console.log('After 1 second');Interview tip: "Promise wrapper around setTimeout. Useful for async/await."
const retry = async (fn, retries = 3) => {
for (let i = 0; i < retries; i++) {
try {
return await fn();
} catch (err) {
if (i === retries - 1) throw err;
}
}
};Interview tip: "Loop with try-catch, throw on final retry."
const promiseAll = promises => {
return new Promise((resolve, reject) => {
const results = [];
let completed = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise).then(value => {
results[index] = value;
completed++;
if (completed === promises.length) resolve(results);
}).catch(reject);
});
});
};Interview tip: "Track completion count, maintain order, reject on first error."
const debounce = (fn, delay) => {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn.apply(this, args), delay);
};
};
// Usage
const debouncedSearch = debounce(() => console.log('Searching...'), 300);Interview tip: "Clear previous timeout, set new one. Good for search inputs."
const throttle = (fn, delay) => {
let lastCall = 0;
return function(...args) {
const now = Date.now();
if (now - lastCall >= delay) {
lastCall = now;
fn.apply(this, args);
}
};
};
// Usage
const throttledScroll = throttle(() => console.log('Scrolling...'), 200);Interview tip: "Track last call time, execute if delay passed. Good for scroll/resize."
// Parallel - faster
const parallel = async () => {
const [result1, result2] = await Promise.all([
fetch('/api/1'),
fetch('/api/2')
]);
};
// Sequential - slower but dependent
const sequential = async () => {
const result1 = await fetch('/api/1');
const result2 = await fetch('/api/2');
};Interview tip: "Use Promise.all for parallel, separate awaits for sequential."
const binarySearch = (arr, target) => {
let left = 0, right = arr.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] === target) return mid;
if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
};
console.log(binarySearch([1, 2, 3, 4, 5], 3)); // 2Interview tip: "O(log n) search on sorted array. Update left/right pointers."
const bubbleSort = arr => {
const n = arr.length;
for (let i = 0; i < n; i++) {
for (let j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
}
return arr;
};
console.log(bubbleSort([5, 3, 8, 4, 2])); // [2, 3, 4, 5, 8]Interview tip: "O(n²) time. Swap adjacent if out of order. Not efficient."
const quickSort = arr => {
if (arr.length <= 1) return arr;
const pivot = arr[arr.length - 1];
const left = arr.filter((x, i) => x <= pivot && i < arr.length - 1);
const right = arr.filter(x => x > pivot);
return [...quickSort(left), pivot, ...quickSort(right)];
};
console.log(quickSort([5, 3, 8, 4, 2])); // [2, 3, 4, 5, 8]Interview tip: "O(n log n) average. Pick pivot, partition, recurse."
const findUnique = arr => arr.filter((val, idx) => arr.indexOf(val) === idx);
console.log(findUnique([1, 2, 2, 3, 4, 4])); // [1, 2, 3, 4]Interview tip: "Filter where first index equals current index."
const mostFrequent = arr => {
const freq = {};
let maxCount = 0, result = null;
arr.forEach(val => {
freq[val] = (freq[val] || 0) + 1;
if (freq[val] > maxCount) {
maxCount = freq[val];
result = val;
}
});
return result;
};
console.log(mostFrequent([1, 3, 2, 3, 3, 1])); // 3Interview tip: "Count frequencies with object, track maximum."
const isValidParentheses = str => {
const stack = [];
const pairs = {'(': ')', '[': ']', '{': '}'};
for (let char of str) {
if (pairs[char]) {
stack.push(char);
} else {
const last = stack.pop();
if (pairs[last] !== char) return false;
}
}
return stack.length === 0;
};
console.log(isValidParentheses("({[]})")); // trueInterview tip: "Use stack. Push opening, pop and match closing."
const generateUUID = () => {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
};
console.log(generateUUID()); // "a3f2b4c5-..."Interview tip: "Replace template with random hex values. Version 4 UUID."
const parseQueryString = url => {
const params = new URLSearchParams(url.split('?')[1]);
return Object.fromEntries(params);
};
console.log(parseQueryString('https://site.com?name=john&age=30'));
// {name: 'john', age: '30'}Interview tip: "Use URLSearchParams and Object.fromEntries for clean solution."
const parseCookies = () => {
return document.cookie.split(';').reduce((acc, cookie) => {
const [key, value] = cookie.trim().split('=');
acc[key] = decodeURIComponent(value);
return acc;
}, {});
};Interview tip: "Split by semicolon, parse key-value pairs, decode URI."
const storage = {
set: (key, value) => localStorage.setItem(key, JSON.stringify(value)),
get: key => JSON.parse(localStorage.getItem(key)),
remove: key => localStorage.removeItem(key),
clear: () => localStorage.clear()
};Interview tip: "Wrap localStorage with JSON parsing for objects."
const formatNumber = num => num.toLocaleString('en-US');
console.log(formatNumber(1234567)); // "1,234,567"
// Manual
const formatManual = num => num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');Interview tip: "Use toLocaleString for internationalization. Regex for custom."
const truncate = (str, length) => str.length > length ? str.slice(0, length) + '...' : str;
console.log(truncate("Hello World", 8)); // "Hello Wo..."Interview tip: "Check length, slice and add ellipsis if needed."
const randomColor = () => '#' + Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0');
console.log(randomColor()); // "#a3f2b4"Interview tip: "Random number 0-16777215 to hex, pad to 6 digits."
const getAge = birthday => {
const today = new Date();
const birth = new Date(birthday);
let age = today.getFullYear() - birth.getFullYear();
const monthDiff = today.getMonth() - birth.getMonth();
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) age--;
return age;
};
console.log(getAge('1990-05-15')); // 34 (as of 2024)Interview tip: "Calculate year difference, adjust for month/day not reached."
const shuffle = arr => {
const result = [...arr];
for (let i = result.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[result[i], result[j]] = [result[j], result[i]];
}
return result;
};
console.log(shuffle([1, 2, 3, 4, 5]));Interview tip: "Fisher-Yates algorithm. Swap random elements backward."
const memoize = fn => {
const cache = {};
return (...args) => {
const key = JSON.stringify(args);
if (key in cache) return cache[key];
cache[key] = fn(...args);
return cache[key];
};
};
const slowFib = n => n <= 1 ? n : slowFib(n - 1) + slowFib(n - 2);
const fastFib = memoize(slowFib);
console.log(fastFib(40)); // Much faster!Interview tip: "Cache results by stringified arguments. Huge performance boost."
// 51. Remove falsy values
const compact = arr => arr.filter(Boolean);
// 52. Get unique by property
const uniqueBy = (arr, key) => [...new Map(arr.map(x => [x[key], x])).values()];
// 53. Pick object properties
const pick = (obj, keys) => Object.fromEntries(keys.map(k => [k, obj[k]]));
// 54. Omit object properties
const omit = (obj, keys) => Object.fromEntries(Object.entries(obj).filter(([k]) => !keys.includes(k)));
// 55. Sleep function
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
// 56. Random integer in range
const randomInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
// 57. Check if empty object
const isEmpty = obj => Object.keys(obj).length === 0;
// 58. Clamp number
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
// 59. Average of array
const average = arr => arr.reduce((a, b) => a + b, 0) / arr.length;
// 60. Range array
const range = (start, end) => Array.from({length: end - start + 1}, (_, i) => start + i);- O(1) - Constant: Direct access, hash lookup
- O(log n) - Logarithmic: Binary search, balanced trees
- O(n) - Linear: Single loop, filter, map
- O(n log n) - Linearithmic: Efficient sorting (merge/quick)
- O(n²) - Quadratic: Nested loops, bubble sort
- O(2ⁿ) - Exponential: Fibonacci recursive
- Clarify - Ask about edge cases, input size, constraints
- Example - Walk through a simple example
- Approach - Explain your strategy before coding
- Code - Write clean, readable code
- Test - Mention edge cases you'd test
- Optimize - Discuss time/space complexity improvements
- "What's the time complexity?" → Always be ready to answer
- "How would you optimize this?" → Discuss trade-offs
- "What if input is very large?" → Talk about performance
- "What edge cases exist?" → null, empty, negative, duplicates
- "I'd add input validation"
- "I'd handle null/undefined cases"
- "I'd write unit tests for this"
- "I could optimize with memoization/caching"
- "I'd use TypeScript for better type safety"
| Problem Type | Best Approach | Time Complexity |
|---|---|---|
| Search sorted | Binary search | O(log n) |
| Search unsorted | Linear/Hash | O(n) or O(1) |
| Sort | Quick/Merge sort | O(n log n) |
| Duplicates | Set/Hash map | O(n) |
| Two pointer | Array problems | O(n) |
| Stack | Parentheses/undo | O(n) |
| Recursion | Tree/divide-conquer | Varies |
| DP/Memo | Optimization | O(n) space |
Good luck with your interviews! 🚀