JavaScript course menu
JavaScript Coding Interview Challenges with Solutions
Common JavaScript coding interview problems with tested solutions: reverse a string, palindromes, FizzBuzz, anagrams, character counts, flatten an array, chunk an array, two sum, debounce, deep equality, group by, and implementing map and Promise.all.
On this page
Coding rounds usually ask you to write small functions while explaining your thinking. Try each problem yourself first. Then compare with the solution, which has been run and shows its real output. Mention the time complexity of your solution; interviewers almost always ask.
1. Reverse a string#
Show solution
const reverse = (s) => [...s].reverse().join("");
console.log(reverse("hello"));
console.log(reverse("ok 👍"));olleh
👍 koSpreading into an array ([...s]) splits by Unicode code points, which handles emoji better than s.split(""). O(n) time.
2. Check for a palindrome#
Ignore case, spaces and punctuation.
Show solution
function isPalindrome(text) {
const clean = text.toLowerCase().replace(/[^a-z0-9]/g, "");
let i = 0;
let j = clean.length - 1;
while (i < j) {
if (clean[i] !== clean[j]) return false;
i++;
j--;
}
return true;
}
console.log(isPalindrome("A man, a plan, a canal: Panama"));
console.log(isPalindrome("JavaScript"));true
falseTwo pointers from both ends: O(n) time, and no reversed copy of the string.
3. FizzBuzz#
Print 1 to 15, but "Fizz" for multiples of 3, "Buzz" for multiples of 5 and "FizzBuzz" for both.
Show solution
const out = [];
for (let n = 1; n <= 15; n++) {
out.push(n % 15 === 0 ? "FizzBuzz" : n % 3 === 0 ? "Fizz" : n % 5 === 0 ? "Buzz" : n);
}
console.log(out.join(" "));1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz4. Count characters and find the most frequent#
Show solution
function mostFrequent(text) {
const counts = new Map();
for (const ch of text.replace(/\s/g, "")) {
counts.set(ch, (counts.get(ch) ?? 0) + 1);
}
let best = null;
for (const [ch, count] of counts) {
if (!best || count > best.count) best = { ch, count };
}
return best;
}
console.log(mostFrequent("javascript is fun"));{ ch: 'a', count: 2 }A Map counts in one pass: O(n). When several characters tie, this returns the first one seen.
5. Are two words anagrams?#
Show solution
function isAnagram(a, b) {
const normalise = (s) => [...s.toLowerCase().replace(/\s/g, "")].sort().join("");
return normalise(a) === normalise(b);
}
console.log(isAnagram("Listen", "Silent"));
console.log(isAnagram("Dormitory", "Dirty room"));
console.log(isAnagram("hello", "world"));true
true
falseSorting is O(n log n). Counting characters with a Map is O(n), which you can mention as an improvement.
6. Flatten a nested array#
Without using flat().
Show solution
function flatten(arr) {
const result = [];
for (const item of arr) {
if (Array.isArray(item)) result.push(...flatten(item));
else result.push(item);
}
return result;
}
console.log(flatten([1, [2, [3, [4]], 5], [[6]]]));[ 1, 2, 3, 4, 5, 6 ]In real code, arr.flat(Infinity) does this.
7. Chunk an array#
Split an array into groups of a given size.
Show solution
function 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, 6, 7], 3));[ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7 ] ]8. Two sum#
Return the indexes of the two numbers that add up to the target.
Show solution
function twoSum(nums, target) {
const seen = new Map(); // value -> index
for (let i = 0; i < nums.length; i++) {
const needed = target - nums[i];
if (seen.has(needed)) return [seen.get(needed), i];
seen.set(nums[i], i);
}
return null;
}
console.log(twoSum([2, 7, 11, 15], 9));
console.log(twoSum([3, 2, 4], 6));
console.log(twoSum([1, 2], 10));[ 0, 1 ]
[ 1, 2 ]
nullA Map of values seen so far gives O(n), instead of the O(n²) nested-loop solution.
9. Group by a key#
Show solution
function groupBy(items, getKey) {
return items.reduce((groups, item) => {
const key = getKey(item);
(groups[key] ??= []).push(item);
return groups;
}, {});
}
const orders = [
{ id: 1, status: "paid" },
{ id: 2, status: "pending" },
{ id: 3, status: "paid" },
];
console.log(groupBy(orders, (o) => o.status));{
paid: [ { id: 1, status: 'paid' }, { id: 3, status: 'paid' } ],
pending: [ { id: 2, status: 'pending' } ]
}Modern JavaScript has Object.groupBy(items, getKey) built in.
10. Deep equality#
Compare two values, including nested objects and arrays.
Show solution
function deepEqual(a, b) {
if (a === b) return true;
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) {
return Number.isNaN(a) && Number.isNaN(b);
}
if (Array.isArray(a) !== Array.isArray(b)) return false;
const keysA = Object.keys(a);
const keysB = Object.keys(b);
if (keysA.length !== keysB.length) return false;
return keysA.every((key) => Object.hasOwn(b, key) && deepEqual(a[key], b[key]));
}
console.log(deepEqual({ a: [1, { b: 2 }] }, { a: [1, { b: 2 }] }));
console.log(deepEqual({ a: 1 }, { a: "1" }));
console.log(deepEqual([1, 2], { 0: 1, 1: 2 }));true
false
falseMention the limits: this ignores prototypes, Dates, Maps and circular references.
11. Implement Array.prototype.map#
Without modifying the real prototype.
Show solution
function myMap(array, callback) {
const result = new Array(array.length);
for (let i = 0; i < array.length; i++) {
result[i] = callback(array[i], i, array);
}
return result;
}
console.log(myMap([1, 2, 3], (n, i) => n * 10 + i));[ 10, 21, 32 ]12. Implement Promise.all#
Show solution
function promiseAll(items) {
return new Promise((resolve, reject) => {
const results = new Array(items.length);
let remaining = items.length;
if (remaining === 0) return resolve(results);
items.forEach((item, i) => {
Promise.resolve(item).then((value) => {
results[i] = value; // keep the original order
remaining--;
if (remaining === 0) resolve(results);
}, reject); // the first rejection rejects everything
});
});
}
const wait = (ms, v) => new Promise((r) => setTimeout(() => r(v), ms));
console.log(await promiseAll([wait(30, "a"), wait(10, "b"), 42]));
try {
await promiseAll([wait(10, "x"), Promise.reject(new Error("failed"))]);
} catch (error) {
console.log(error.message);
}[ 'a', 'b', 42 ]
failedKey points: results stay in input order, non-promise values are accepted (via Promise.resolve), and an empty array resolves immediately.
Keep going#
Review the intermediate and advanced questions, or practise more problems in the practice section.
Finished this lesson?