📖 21 min read
Last updated on

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.

Stick figure holding a magnifying glass and sweating profusely trying to figure out if two things are strictly equal ===

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 ([] == 0 is 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).


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

TaskSnippet
Max of arrayMath.max(...arr)
Min of arrayMath.min(...arr)
Sort ascendingarr.sort((a, b) => a - b)
Sort descendingarr.sort((a, b) => b - a)
Non-mutating sort[...arr].sort((a, b) => a - b)
Reversearr.reverse() / arr.toReversed()
Deduplicate[...new Set(arr)]
Flattenarr.flat() / arr.flat(Infinity)
Sumarr.reduce((a, b) => a + b, 0)
Frequency mapmap.set(x, (map.get(x) ?? 0) + 1)
Init 2D arrayArray.from({length: r}, () => new Array(c).fill(0))
Init index arrayArray.from({length: n}, (_, i) => i)
Swap[a, b] = [b, a]
Last elementarr.at(-1)
Check oddx & 1
Floor div(a / b) | 0
GCDconst gcd = (a, b) => b ? gcd(b, a % b) : a
InfinityInfinity / -Infinity
BFS queue trickUse index pointer to avoid shift()
Build graph (obj)(graph[u] ??= []).push(v)
Backtrack snapshotresult.push([...path]) — always spread!
Safe regex testconst ok = /pattern/.test(s) — not s.test = ...

Common JavaScript Interview Gotchas

These are the traps that catch even experienced developers in JavaScript coding interviews:

GotchaWrongRight
Numeric sortarr.sort()arr.sort((a,b) => a-b)
Equalitya == ba === b
Array copyconst b = aconst b = [...a]
2D array initnew Array(r).fill([])Array.from({length:r}, () => [])
Check NaNx === NaNNumber.isNaN(x)
typeof nulltypeof null === "null"typeof null === "object"
Integer divisiona / bMath.floor(a / b)
Queue dequeuearr.shift() (O(n))Use index pointer

Solid on JavaScript fundamentals? The next step is applying these tools to the core problem categories:

  • Arrays & HashingMap frequency maps, Set for O(1) lookup, sliding window
  • Binary Search — implement lowerBound/upperBound from 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 →

Practice Like It's the Real Interview

Get instant feedback on your approach, communication, and code — powered by AI.

Start a Mock Interview →