JavaScript Coding Interview Cheat Sheet — Complete Syntax & Patterns Guide
A practical, no-fluff guide to the JavaScript syntax, built-ins, and patterns you’ll actually reach for during a live coding interview.
Why JavaScript for Coding Interviews?
JavaScript is increasingly accepted — and even preferred — in coding interviews, especially for frontend and full-stack roles. Here is why it’s a double-edged sword:
- Ubiquity: If you work on the web, you already know JavaScript (or TypeScript). You don’t need to learn a separate language just for interviews.
- First-Class Functions: Callbacks, array methods (
map,filter,reduce), and closures make concise functional programming possible. - The Quirk Factor: JavaScript’s loose typing, reference semantics, and type coercion (
[] == 0is true) can cause bizarre bugs under pressure. You must know when to be defensive (===,.padStart). - Missing Built-ins: JavaScript does not have a native Priority Queue (min/max heap). You will need to bring your own implementation or work around it using sorting!
If you're building your full preparation plan, start with our How to Prepare for a Coding Interview guide. This also pairs perfectly with Data Structures for Coding Interviews.
Looking for a different language? Python, Java, C++, Go.
Already know why JavaScript? Try a free JavaScript mock interview on Intervu →
1. Data Types & Variables
// Variable declarations
const x = 10; // block-scoped, immutable binding
let y = 20; // block-scoped, mutable
// var z = 30; // function-scoped — avoid in modern JS
// Primitives
const n = 42;
const big = BigInt(Number.MAX_SAFE_INTEGER) + 1n; // arbitrary precision
const f = 3.14;
const b = true; // true / false
const s = "hello";
const nothing = null;
const undef = undefined;
// Special numeric values
Number.MAX_SAFE_INTEGER // 2^53 - 1 (9007199254740991)
Number.MIN_SAFE_INTEGER // -(2^53 - 1)
Infinity // positive infinity
-Infinity
NaN // not a number — NaN !== NaN !
// Infinity proxies for interviews
const INF = Infinity;
const NEG_INF = -Infinity;
// Type checks
typeof 42 // "number"
typeof "hi" // "string"
typeof true // "boolean"
typeof null // "object" ← famous JS quirk
typeof undefined // "undefined"
typeof [] // "object"
Array.isArray([]) // true ← correct way to check array
// Equality — always use === in interviews
1 == "1" // true (loose, coerces types)
1 === "1" // false (strict, no coercion)
null == undefined // true (loose)
null === undefined // false (strict)
// Falsy values (all evaluate to false in boolean context)
// false, 0, "", null, undefined, NaN
Boolean(0) // false
Boolean("") // false
Boolean([]) // true ← arrays are truthy even if empty!
Boolean({}) // true ← objects too
Key tip: JavaScript numbers are 64-bit floats. Integers are only safe up to 2^53 - 1 — beyond that, use BigInt. For most interview problems, Number is fine, but watch for problems with very large values.
2. Strings
const s = "hello world";
// Basics
s.length // 11
s[0] // 'h'
s[s.length - 1] // 'd'
s.at(-1) // 'd' (ES2022 — cleaner)
s.slice(6) // "world"
s.slice(1, 5) // "ello" [start, end)
s.slice(-5) // "world" (from end)
// Search
s.indexOf("world") // 6 (-1 if not found)
s.lastIndexOf('o') // 7
s.includes("world") // true
s.startsWith("he") // true
s.endsWith("ld") // true
// Transform
s.toUpperCase() // "HELLO WORLD"
s.toLowerCase() // "hello world"
s.trim() // remove leading/trailing whitespace
s.trimStart() / s.trimEnd()
s.replace("world", "there") // replaces first occurrence
s.replaceAll("l", "r") // replaces all
s.repeat(3) // "hello worldhello worldhello world"
s.padStart(10, '0') // "000hello w"
s.padEnd(10, '-') // "hello worl--"
// Split & Join
s.split(" ") // ["hello", "world"]
s.split("") // ["h","e","l","l","o",...] — each char
"a,b,c".split(",") // ["a","b","c"]
["a","b","c"].join("-") // "a-b-c"
["a","b","c"].join("") // "abc"
// Template literals
const name = "Alice", score = 42;
`${name} scored ${score} points` // "Alice scored 42 points"
`${score > 40 ? "pass" : "fail"}` // expression inside ${}
// Char codes
s.charCodeAt(0) // 104 ('h')
String.fromCharCode(104) // 'h'
'a'.charCodeAt(0) // 97
'z'.charCodeAt(0) - 'a'.charCodeAt(0) // 25
// String → array of chars and back
const chars = [...s]; // spread into array
const back = chars.join(""); // back to string
// Regex
s.match(/\d+/g) // array of all matches (null if none)
const isMatch = /pattern/.test(s) // true/false — don't assign to s.test!
s.replace(/\s+/g, "_") // replace all whitespace with _
Key tip: Strings are immutable in JavaScript. s[0] = 'H' does nothing. To modify, spread into an array, change the element, then rejoin: [...s] → modify → .join("").
3. Arrays
Arrays are the most common data structure in JavaScript coding interviews. Know these methods cold.
const arr = [3, 1, 4, 1, 5, 9];
// Access
arr[0] // 3
arr[arr.length - 1] // 9
arr.at(-1) // 9 (ES2022)
// Modify (mutating)
arr.push(2) // append — O(1) amortized, returns new length
arr.pop() // remove & return last — O(1)
arr.unshift(0) // prepend — O(n), returns new length
arr.shift() // remove & return first — O(n)
arr.splice(2, 1) // remove 1 element at index 2
arr.splice(2, 0, 99) // insert 99 at index 2
arr.splice(2, 1, 99) // replace element at index 2 with 99
arr.reverse() // reverse in-place, returns arr
arr.fill(0) // fill all with 0
arr.fill(0, 2, 5) // fill indices [2, 5) with 0
// Non-mutating (return new array)
arr.slice(1, 4) // [1, 4, 1] [start, end)
arr.slice(-3) // last 3 elements
arr.concat([6, 7]) // append elements, returns new array
[...arr, 6, 7] // same with spread
// Search
arr.indexOf(1) // 1 (first index, -1 if missing)
arr.lastIndexOf(1) // 3
arr.includes(5) // true
arr.find(x => x > 4) // 5 (first match, undefined if none)
arr.findIndex(x => x > 4) // 4 (first matching index, -1 if none)
// Info
arr.length
// Initialize
new Array(5).fill(0) // [0, 0, 0, 0, 0]
Array.from({length: 5}, (_, i) => i) // [0, 1, 2, 3, 4]
Array.from({length: 5}, (_, i) => i * 2) // [0, 2, 4, 6, 8]
// 2D array
const matrix = Array.from({length: rows}, () => new Array(cols).fill(0));
// Don't use: new Array(rows).fill([]) ← all rows share same reference!
// Stack (use push/pop)
const stack = [];
stack.push(val); // push
stack.pop(); // pop
// Queue (use push/shift — shift is O(n))
const queue = [];
queue.push(val); // enqueue
queue.shift(); // dequeue — O(n)
// For O(1) dequeue, implement with two stacks or use an index pointer
// Flatten
[[1,2],[3,4]].flat() // [1, 2, 3, 4]
[[1,[2,3]],[4]].flat(2) // [1, 2, 3, 4] (depth 2)
arr.flat(Infinity) // fully flatten any depth
Key tip: Array.from({length: rows}, () => new Array(cols).fill(0)) is the correct way to make a 2D array. Using new Array(rows).fill([]) is a common bug — all rows point to the same inner array.
4. Objects
const obj = { a: 1, b: 2, c: 3 };
// Access
obj.a // 1
obj["a"] // 1 (use when key is dynamic)
obj.z // undefined (no error)
obj.z ?? "default" // "default" (nullish coalescing)
// Modify
obj.d = 4; // add
obj.a = 10; // update
delete obj.a; // remove
// Check
"b" in obj // true
obj.hasOwnProperty("b") // true
// Iterate
Object.keys(obj) // ["a", "b", "c"]
Object.values(obj) // [1, 2, 3]
Object.entries(obj) // [["a",1], ["b",2], ["c",3]]
for (const [key, val] of Object.entries(obj)) {
console.log(key, val);
}
// Build from entries
Object.fromEntries([["a", 1], ["b", 2]]) // {a: 1, b: 2}
Object.fromEntries(map) // Map → Object
// Copy & merge
const copy = { ...obj }; // shallow copy
const merged = { ...obj1, ...obj2 }; // merge (obj2 wins on conflicts)
const withExtra = { ...obj, d: 4 }; // copy + add field
// Frequency map pattern
const freq = {};
for (const ch of s) {
freq[ch] = (freq[ch] ?? 0) + 1;
}
// Adjacency list pattern
const graph = {};
graph[u] = graph[u] ?? [];
graph[u].push(v);
Key tip: Objects in JavaScript are passed by reference. const b = a (where a is an object) does not copy — both variables point to the same object. Use { ...a } for a shallow copy.
5. Map & Set
Prefer Map over plain objects for frequency maps and graph adjacency in interviews — it has guaranteed insertion-order iteration and cleaner APIs.
// Map — ordered key-value pairs, any key type
const map = new Map();
map.set("alice", 10);
map.set("bob", 20);
map.get("alice") // 10
map.get("zz") // undefined
map.has("alice") // true
map.delete("bob")
map.size // 1 (property, not method)
map.clear()
// Safe default
map.get(key) ?? 0
// Frequency map
const freq = new Map();
for (const x of arr) {
freq.set(x, (freq.get(x) ?? 0) + 1);
}
// Iterate (insertion order)
for (const [key, val] of map) { }
for (const key of map.keys()) { }
for (const val of map.values()) { }
map.forEach((val, key) => { }); // note: val first, then key
// Initialize from array of pairs
const m = new Map([["a", 1], ["b", 2]]);
// Convert
[...map.entries()] // array of [key, val] pairs
[...map.keys()]
[...map.values()]
Object.fromEntries(map) // Map → plain object (string keys only)
// Set — unordered, unique values
const set = new Set([1, 2, 3, 3]); // Set {1, 2, 3}
set.add(4);
set.delete(2);
set.has(3) // true — O(1)
set.size // 3
// Iterate
for (const x of set) { }
[...set] // convert to array
// Set operations
const union = new Set([...a, ...b]);
const intersection = new Set([...a].filter(x => b.has(x)));
const difference = new Set([...a].filter(x => !b.has(x)));
// Deduplicate array
const unique = [...new Set(arr)];
6. Control Flow
// if / else if / else
if (x > 0) { }
else if (x === 0) { }
else { }
// Ternary
const result = x > 0 ? "pos" : "non-pos";
// Nullish coalescing (??) — only null/undefined triggers default
const val = x ?? "default"; // "default" only if x is null/undefined
// Optional chaining (?.)
obj?.nested?.value // undefined instead of TypeError
arr?.[0]
fn?.()
// Logical assignment
x ??= 0; // assign 0 if x is null/undefined
x ||= 0; // assign 0 if x is falsy
x &&= fn(x); // apply fn only if x is truthy
// for loop
for (let i = 0; i < n; i++) { }
for (let i = n - 1; i >= 0; i--) { }
// for...of — iterate values (arrays, strings, Maps, Sets)
for (const x of arr) { }
for (const ch of str) { }
for (const [k, v] of map) { }
// for...in — iterate keys (objects) — avoid for arrays
for (const key in obj) { }
// while
while (condition) { }
// break / continue
for (let i = 0; i < n; i++) {
if (i === 5) break;
if (i % 2 === 0) continue;
}
// Labeled break (for nested loops)
outer: for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (grid[i][j] === target) break outer;
}
}
7. Functions & Arrow Functions
// Function declaration (hoisted)
function add(a, b) {
return a + b;
}
// Function expression (not hoisted)
const add = function(a, b) {
return a + b;
};
// Arrow function (concise, lexical this)
const add = (a, b) => a + b; // implicit return
const square = x => x * x; // single param, no parens needed
const greet = () => "hello"; // no params
// Default parameters
const greet = (name = "World") => `Hello, ${name}!`;
// Rest parameters
const sum = (...nums) => nums.reduce((a, b) => a + b, 0);
sum(1, 2, 3, 4); // 10
// Destructuring parameters
const display = ({ name, score }) => `${name}: ${score}`;
const first = ([a, b]) => a;
// Closures (capture variables from outer scope)
const makeCounter = () => {
let count = 0;
return () => ++count;
};
const counter = makeCounter();
counter(); // 1
counter(); // 2
// Immediately Invoked Function Expression (IIFE)
const result = ((x) => x * x)(5); // 25
// Recursive function
const fib = (n) => n <= 1 ? n : fib(n - 1) + fib(n - 2);
// Higher-order functions
const apply = (fn, x) => fn(x);
apply(x => x * 2, 5); // 10
8. Array Methods (Functional Style)
These are among the most powerful tools in a JavaScript coding interview. Know them well.
const arr = [1, 2, 3, 4, 5];
// map — transform each element (returns new array)
arr.map(x => x * 2) // [2, 4, 6, 8, 10]
arr.map((x, i) => [i, x]) // [[0,1],[1,2],...]
// filter — keep elements matching predicate
arr.filter(x => x % 2 === 0) // [2, 4]
// reduce — accumulate to single value
arr.reduce((acc, x) => acc + x, 0) // 15 (sum)
arr.reduce((acc, x) => acc * x, 1) // 120 (product)
arr.reduce((acc, x) => Math.max(acc, x), -Infinity) // max
// Frequency map with reduce
const freq = arr.reduce((acc, x) => {
acc[x] = (acc[x] ?? 0) + 1;
return acc;
}, {});
// reduceRight — reduce from right to left
arr.reduceRight((acc, x) => acc + x, 0)
// find / findIndex
arr.find(x => x > 3) // 4
arr.findIndex(x => x > 3) // 3
// some / every
arr.some(x => x > 4) // true (at least one)
arr.every(x => x > 0) // true (all)
// flat / flatMap
[[1,2],[3,4]].flat() // [1, 2, 3, 4]
arr.flatMap(x => [x, x * 2]) // [1,2, 2,4, 3,6, 4,8, 5,10]
// forEach — side effects only, returns undefined
arr.forEach((x, i) => console.log(i, x));
// Chaining
const result = arr
.filter(x => x % 2 !== 0) // [1, 3, 5]
.map(x => x * x) // [1, 9, 25]
.reduce((a, b) => a + b, 0); // 35
// entries / keys / values — returns iterators
for (const [i, x] of arr.entries()) { }
9. Sorting
JavaScript’s default sort() converts elements to strings and sorts lexicographically — always provide a comparator for numbers.
const arr = [10, 9, 2, 21, 3];
// WRONG — lexicographic sort!
arr.sort() // [10, 2, 21, 3, 9]
// Correct numeric sorts
arr.sort((a, b) => a - b) // ascending: [2, 3, 9, 10, 21]
arr.sort((a, b) => b - a) // descending: [21, 10, 9, 3, 2]
// Sort strings
["banana","fig","apple"].sort() // lexicographic (correct for strings)
["banana","fig","apple"].sort((a, b) => a.length - b.length) // by length
// Sort array of objects
const people = [{name:"Bob",age:25},{name:"Alice",age:30}];
people.sort((a, b) => a.age - b.age) // by age asc
people.sort((a, b) => a.name.localeCompare(b.name)) // by name
// Sort by multiple keys
people.sort((a, b) => {
if (a.age !== b.age) return a.age - b.age;
return a.name.localeCompare(b.name); // tie-break by name
});
// Sort array of arrays by first element, then second
const pairs = [[1,3],[2,1],[1,2]];
pairs.sort((a, b) => a[0] !== b[0] ? a[0] - b[0] : a[1] - b[1]);
// Non-mutating sort (ES2023)
const sorted = arr.toSorted((a, b) => a - b); // returns new array
const rev = arr.toReversed(); // non-mutating reverse
// Get sorted indices (argsort)
const indices = Array.from({length: arr.length}, (_, i) => i);
indices.sort((a, b) => arr[a] - arr[b]);
Key tip: sort() mutates the original array. If you need the original order preserved, sort a copy: [...arr].sort((a, b) => a - b).
10. Binary Search
JavaScript has no built-in binary search — implement the templates from memory.
// Standard binary search
function binarySearch(arr, target) {
let lo = 0, hi = arr.length - 1;
while (lo <= hi) {
const mid = (lo + hi) >> 1; // same as Math.floor((lo+hi)/2)
if (arr[mid] === target) return mid;
else if (arr[mid] < target) lo = mid + 1;
else hi = mid - 1;
}
return -1;
}
// Left bound — first index where arr[i] >= target
function lowerBound(arr, target) {
let lo = 0, hi = arr.length;
while (lo < hi) {
const mid = (lo + hi) >> 1;
if (arr[mid] < target) lo = mid + 1;
else hi = mid;
}
return lo; // lo === arr.length if target > all elements
}
// Right bound — first index where arr[i] > target
function upperBound(arr, target) {
let lo = 0, hi = arr.length;
while (lo < hi) {
const mid = (lo + hi) >> 1;
if (arr[mid] <= target) lo = mid + 1;
else hi = mid;
}
return lo;
}
// Count occurrences in sorted array
const count = upperBound(arr, target) - lowerBound(arr, target);
// Floor: largest value <= target
function floor(arr, target) {
const i = upperBound(arr, target) - 1;
return i >= 0 ? arr[i] : undefined;
}
// Binary search on answer (monotonic predicate)
let lo = 0, hi = 1e9;
while (lo < hi) {
const mid = Math.floor((lo + hi) / 2);
if (feasible(mid)) hi = mid;
else lo = mid + 1;
}
// lo is the minimum feasible value
11. Math & Numbers
// Math methods
Math.max(a, b) // max of arguments
Math.min(a, b)
Math.max(...arr) // max of array (spread)
Math.min(...arr)
Math.abs(x)
Math.pow(2, 10) // 1024
Math.sqrt(16) // 4
Math.floor(3.7) // 3
Math.ceil(3.2) // 4
Math.round(3.5) // 4
Math.trunc(3.9) // 3 (truncate toward zero)
Math.log(x) // natural log
Math.log2(x)
Math.log10(x)
Math.PI // 3.14159...
// Integer check
Number.isInteger(4.0) // true
Number.isInteger(4.5) // false
// NaN check (NaN !== NaN!)
Number.isNaN(NaN) // true (preferred)
isNaN("hello") // true (coerces — avoid)
// Modular arithmetic
((a % m) + m) % m // always-positive modulo
const MOD = 1e9 + 7;
// Integer division
Math.floor(a / b) // works for positive numbers
(a / b) | 0 // truncates toward zero (bitwise)
~~(a / b) // same (double NOT)
// GCD (no built-in — write your own)
const gcd = (a, b) => b === 0 ? a : gcd(b, a % b);
const lcm = (a, b) => (a / gcd(a, b)) * b;
// Clamp
const clamp = (x, lo, hi) => Math.max(lo, Math.min(hi, x));
// Infinity
Infinity + 1 // Infinity
1 / 0 // Infinity
-1 / 0 // -Infinity
0 / 0 // NaN
12. Bit Manipulation
// Bitwise operators
x & y // AND
x | y // OR
x ^ y // XOR
~x // NOT (bitwise complement — ~x = -(x+1))
x << k // left shift
x >> k // arithmetic right shift (sign-preserving)
x >>> k // logical right shift (zero-fill) — use for unsigned
// Useful tricks
x & 1 // check if odd
x & (x - 1) // clear lowest set bit
x & (-x) // isolate lowest set bit
x ^ x // 0
x ^ 0 // x
// Power of 2 check
const isPow2 = x > 0 && (x & (x - 1)) === 0;
// Count set bits (no built-in in plain JS)
const popcount = x => {
let count = 0;
while (x) { x &= x - 1; count++; }
return count;
};
// Set / clear / toggle / read bit k
x |= (1 << k) // set bit k
x &= ~(1 << k) // clear bit k
x ^= (1 << k) // toggle bit k
(x >> k) & 1 // read bit k
// Fast floor division by 2
x >> 1
// Fast integer conversion (truncate)
x | 0
~~x
// Iterate all subsets of n elements
for (let mask = 0; mask < (1 << n); mask++) {
for (let i = 0; i < n; i++) {
if (mask & (1 << i)) {
// element i is in this subset
}
}
}
Key tip: JavaScript bitwise operators work on 32-bit signed integers. Numbers are implicitly converted to 32-bit int before the operation, then back to JS number. This means ~0 === -1 and very large numbers can behave unexpectedly — stick to values within 32-bit range for bit tricks.
13. Destructuring, Spread & Rest
These are core modern JavaScript features that make interview code cleaner and more readable.
// Array destructuring
const [a, b, c] = [1, 2, 3];
const [first, ...rest] = [1, 2, 3, 4]; // rest = [2, 3, 4]
const [, second] = [1, 2, 3]; // skip first
const [x = 0, y = 0] = [5]; // default values
// Swap
let p = 1, q = 2;
[p, q] = [q, p]; // swap without temp variable
// Object destructuring
const { name, age } = person;
const { name: n, age: a } = person; // rename
const { x: px = 0, y: py = 0 } = point; // rename + default
const { a: aa, ...remaining } = obj; // rest in object
// Nested
const { address: { city } } = person;
// In function parameters
const display = ({ name, score = 0 }) => `${name}: ${score}`;
const head = ([first]) => first;
// Spread — expand iterable into individual elements
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
const copy = [...arr1]; // shallow copy
const merged = [...arr1, ...arr2];
Math.max(...arr1) // spread into function args
// Object spread
const obj2 = { ...obj1, extra: true }; // copy + add fields
const updated = { ...obj, key: newVal }; // copy + override
// Rest in function
const sum = (first, ...rest) => rest.reduce((a, b) => a + b, first);
14. Classes & Linked List Nodes
// Class syntax
class ListNode {
constructor(val, next = null) {
this.val = val;
this.next = next;
}
}
class TreeNode {
constructor(val, left = null, right = null) {
this.val = val;
this.left = left;
this.right = right;
}
}
// Build a linked list from array
function arrayToList(arr) {
let dummy = new ListNode(0);
let cur = dummy;
for (const val of arr) {
cur.next = new ListNode(val);
cur = cur.next;
}
return dummy.next;
}
// General class
class MinStack {
constructor() {
this.stack = [];
this.minStack = [];
}
push(val) {
this.stack.push(val);
const min = this.minStack.length === 0
? val
: Math.min(val, this.minStack.at(-1));
this.minStack.push(min);
}
pop() {
this.stack.pop();
this.minStack.pop();
}
top() { return this.stack.at(-1); }
getMin() { return this.minStack.at(-1); }
}
// Inheritance
class Animal {
constructor(name) { this.name = name; }
speak() { return `${this.name} makes a sound.`; }
}
class Dog extends Animal {
speak() { return `${this.name} barks.`; }
}
15. Common Algorithm Patterns
These are the templates behind the majority of JavaScript coding interview problems. Memorize them, then practice under time pressure.
Two Pointers
function twoSumSorted(arr, target) {
let l = 0, r = arr.length - 1;
while (l < r) {
const sum = arr[l] + arr[r];
if (sum === target) return [l, r];
else if (sum < target) l++;
else r--;
}
return [];
}
Sliding Window
function maxSumSubarray(arr, k) {
let window = arr.slice(0, k).reduce((a, b) => a + b, 0);
let best = window;
for (let i = k; i < arr.length; i++) {
window += arr[i] - arr[i - k];
best = Math.max(best, window);
}
return best;
}
Fast & Slow Pointers
function hasCycle(head) {
let slow = head, fast = head;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) return true;
}
return false;
}
BFS Template
function bfs(graph, start) {
const visited = new Set([start]);
const queue = [start];
let qi = 0; // index pointer avoids O(n) shift
while (qi < queue.length) {
const node = queue[qi++];
for (const neighbor of (graph[node] ?? [])) {
if (!visited.has(neighbor)) {
visited.add(neighbor);
queue.push(neighbor);
}
}
}
}
DFS Template (Recursive)
function dfs(graph, node, visited = new Set()) {
visited.add(node);
for (const neighbor of (graph[node] ?? [])) {
if (!visited.has(neighbor)) {
dfs(graph, neighbor, visited);
}
}
}
DFS Template (Iterative)
function dfs(graph, start) {
const visited = new Set();
const stack = [start];
while (stack.length) {
const node = stack.pop();
if (visited.has(node)) continue;
visited.add(node);
for (const neighbor of (graph[node] ?? [])) {
stack.push(neighbor);
}
}
}
Binary Search on Answer
let lo = 0, hi = 1e9;
while (lo < hi) {
const mid = Math.floor((lo + hi) / 2);
if (feasible(mid)) hi = mid;
else lo = mid + 1;
}
// lo is the minimum feasible value
Dynamic Programming — Memoization
function solve(n, memo = new Map()) {
if (n <= 1) return n;
if (memo.has(n)) return memo.get(n);
const result = solve(n - 1, memo) + solve(n - 2, memo);
memo.set(n, result);
return result;
}
// Or with a closure
function makeDP() {
const memo = {};
return function dp(i, j) {
const key = `${i},${j}`;
if (key in memo) return memo[key];
// ... compute result
return memo[key] = result;
};
}
Prefix Sum
function buildPrefix(arr) {
const prefix = new Array(arr.length + 1).fill(0);
for (let i = 0; i < arr.length; i++)
prefix[i + 1] = prefix[i] + arr[i];
return prefix;
}
// Range sum [l, r] inclusive: prefix[r+1] - prefix[l]
Monotonic Stack
function nextGreater(arr) {
const result = new Array(arr.length).fill(-1);
const stack = []; // stores indices
for (let i = 0; i < arr.length; i++) {
while (stack.length && arr[i] > arr[stack.at(-1)]) {
result[stack.pop()] = arr[i];
}
stack.push(i);
}
return result;
}
Union-Find
class UnionFind {
constructor(n) {
this.parent = Array.from({length: n}, (_, i) => i);
this.rank = new Array(n).fill(0);
}
find(x) {
if (this.parent[x] !== x)
this.parent[x] = this.find(this.parent[x]); // path compression
return this.parent[x];
}
unite(x, y) {
let px = this.find(x), py = this.find(y); // must be let, not const
if (px === py) return false;
if (this.rank[px] < this.rank[py]) [px, py] = [py, px]; // swap
this.parent[py] = px;
if (this.rank[px] === this.rank[py]) this.rank[px]++;
return true;
}
connected(x, y) { return this.find(x) === this.find(y); }
}
Building a Graph from an Edge List
The BFS/DFS templates use graph[node] — here’s how to build it with both object and Map:
// Using plain object (works for integer nodes)
const graph = {};
for (const [u, v] of edges) {
(graph[u] ??= []).push(v);
(graph[v] ??= []).push(u); // omit for directed
}
// Using Map (works for any key type)
const graph = new Map();
for (const [u, v] of edges) {
if (!graph.has(u)) graph.set(u, []);
if (!graph.has(v)) graph.set(v, []);
graph.get(u).push(v);
graph.get(v).push(u); // omit for directed
}
Backtracking Template
Use for subsets, permutations, combinations, N-Queens, and word search:
const result = [];
function backtrack(start, path) {
result.push([...path]); // snapshot — spread to avoid reference sharing
for (let i = start; i < nums.length; i++) {
path.push(nums[i]); // choose
backtrack(i + 1, path); // explore (use i for repetition allowed)
path.pop(); // undo (backtrack)
}
}
backtrack(0, []);
Key tip: Always spread [...path] when adding to result. Pushing path directly means every entry in result will be the same mutating array.
Trie (Prefix Tree)
Used for word search, autocomplete, and prefix-matching problems:
class TrieNode {
constructor() {
this.children = new Map();
this.isEnd = false;
}
}
class Trie {
constructor() { this.root = new TrieNode(); }
insert(word) {
let node = this.root;
for (const ch of word) {
if (!node.children.has(ch))
node.children.set(ch, new TrieNode());
node = node.children.get(ch);
}
node.isEnd = true;
}
search(word) {
let node = this.root;
for (const ch of word) {
if (!node.children.has(ch)) return false;
node = node.children.get(ch);
}
return node.isEnd;
}
startsWith(prefix) {
let node = this.root;
for (const ch of prefix) {
if (!node.children.has(ch)) return false;
node = node.children.get(ch);
}
return true;
}
}
Quick Reference Cheat Sheet
| Task | Snippet |
|---|---|
| Max of array | Math.max(...arr) |
| Min of array | Math.min(...arr) |
| Sort ascending | arr.sort((a, b) => a - b) |
| Sort descending | arr.sort((a, b) => b - a) |
| Non-mutating sort | [...arr].sort((a, b) => a - b) |
| Reverse | arr.reverse() / arr.toReversed() |
| Deduplicate | [...new Set(arr)] |
| Flatten | arr.flat() / arr.flat(Infinity) |
| Sum | arr.reduce((a, b) => a + b, 0) |
| Frequency map | map.set(x, (map.get(x) ?? 0) + 1) |
| Init 2D array | Array.from({length: r}, () => new Array(c).fill(0)) |
| Init index array | Array.from({length: n}, (_, i) => i) |
| Swap | [a, b] = [b, a] |
| Last element | arr.at(-1) |
| Check odd | x & 1 |
| Floor div | (a / b) | 0 |
| GCD | const gcd = (a, b) => b ? gcd(b, a % b) : a |
| Infinity | Infinity / -Infinity |
| BFS queue trick | Use index pointer to avoid shift() |
| Build graph (obj) | (graph[u] ??= []).push(v) |
| Backtrack snapshot | result.push([...path]) — always spread! |
| Safe regex test | const ok = /pattern/.test(s) — not s.test = ... |
Common JavaScript Interview Gotchas
These are the traps that catch even experienced developers in JavaScript coding interviews:
| Gotcha | Wrong | Right |
|---|---|---|
| Numeric sort | arr.sort() | arr.sort((a,b) => a-b) |
| Equality | a == b | a === b |
| Array copy | const b = a | const b = [...a] |
| 2D array init | new Array(r).fill([]) | Array.from({length:r}, () => []) |
| Check NaN | x === NaN | Number.isNaN(x) |
| typeof null | typeof null === "null" | typeof null === "object" |
| Integer division | a / b | Math.floor(a / b) |
| Queue dequeue | arr.shift() (O(n)) | Use index pointer |
Related Interview Topics
Solid on JavaScript fundamentals? The next step is applying these tools to the core problem categories:
- Arrays & Hashing —
Mapfrequency maps,Setfor O(1) lookup, sliding window - Binary Search — implement
lowerBound/upperBoundfrom scratch, binary search on answer - Trees & Graphs — BFS with queue index trick, recursive DFS, level-order traversal
- Dynamic Programming — memoization with
Map, key encoding for multi-dimensional states - Intervals & Greedy — sorting with custom comparators, sweep line
Each of these patterns has dedicated walkthroughs on the Intervu blog.
Practice Under Real Interview Conditions
You now have the JavaScript syntax and patterns — but coding interviews test how you apply them under pressure, not how well you read. Fluency in Array.prototype methods means nothing if you freeze when asked to implement a BFS on a grid with a 20-minute clock.
Close that gap with deliberate practice. Intervu gives you AI-powered mock coding interviews that simulate the real experience — timed, with follow-up questions, and instant feedback on your reasoning, edge case handling, and code clarity.
Ready to put it to the test? Start a free mock interview on Intervu →