JavaScript Interview Cheat Sheet: The Idioms That Save Time

May 29, 202610 min read
dsaalgorithmsinterview-prepleetcode
TL;DR
  • Destructuring defaults only fire on undefined, not null — a silent bug when APIs return explicit nulls
  • ?? vs ||: nullish coalescing short-circuits only on null/undefined, keeping 0 and "" as valid values
  • structuredClone replaces the broken JSON.parse(JSON.stringify()) pattern for deep copies (Node 17+)
  • Array.prototype.sort mutates and sorts lexicographically by default — clone first and always pass a comparator
  • Number.isNaN is the safe check; the global isNaN coerces its argument first, producing false positives on strings
  • Object.fromEntries(Object.entries().map()) is the idiomatic way to transform object values without mutation
  • ?? and ?. cannot mix with ||/&& without parentheses — JavaScript throws a SyntaxError at parse time

You have 45 minutes. One problem, maybe two. The algorithm clicks in the first five. Then you spend the next eight re-deriving the comparator syntax for .sort, blanking on whether .find returns the element or the index, and staring at ?? like it owes you money.

That is the real cost of not knowing your language cold. Not wrong answers. Wasted time on stuff you already know. This cheat sheet covers the JavaScript idioms worth burning into muscle memory before you sit down.


Destructuring Is Four Lines Collapsed Into One

Array and object destructuring both work exactly the way you want, with one non-obvious rule: default values only kick in for undefined, not null.

// Object destructuring with rename and default const { name: userName = "anonymous", score = 0 } = user; // Array destructuring with skip const [first, , third] = [1, 2, 3]; // Swap without a temp variable let a = 1, b = 2; [a, b] = [b, a]; // The gotcha: null does NOT trigger the default const { x = 10 } = { x: null }; console.log(x); // null, not 10

This matters in interviews when you're destructuring API-style objects. The distinction is intentional: undefined means "this slot was never filled," null means "it was filled with emptiness on purpose." Defaults fire for one. APIs return the other. Your defaults quietly don't fire, and the bug is silent.

Nested destructuring works too, but keep it one level deep in interviews. Beyond that it reads like a puzzle, not code.


Spread and Rest: Clone Without the Object.assign Dance

The spread operator handles three different jobs. Knowing all three saves meaningful time.

// Shallow clone an array or object const copy = [...original]; const objCopy = { ...obj }; // Merge objects (right side wins on conflict) const merged = { ...defaults, ...overrides }; // Collect remaining arguments function sum(first, ...rest) { return rest.reduce((acc, n) => acc + n, first); }

Spread is shallow. For interviews where you need a true deep copy, structuredClone is the right call since 2022 and is available in Node 17+ and all modern browsers.

const deep = structuredClone(nested); // works on objects, arrays, Maps, Sets

JSON.parse(JSON.stringify(x)) is the old answer. It works in the happy path and silently breaks on undefined, functions, Date objects, and circular references. Don't use it. The interviewer will know you used it. Worse, the production bug will.


The ?? and ?. Pair Replaces Three Guard Clauses

These two operators solve different halves of the same problem: safely navigating data you don't fully trust. Most engineers know ?.. Fewer know when to use ?? instead of ||, and that gap causes exactly one bug per codebase.

The critical difference between ?? and || is that || treats 0, "", and false as falsy, but ?? only short-circuits on null and undefined.

// ?? for safe defaults when 0 or "" are valid values const count = data.count ?? 0; // 0 stays 0 const label = data.label ?? ""; // "" stays "" // || would silently replace valid zeros const count2 = data.count || 0; // data.count=0 becomes 0 anyway, but for wrong reason // ?. for safe property traversal const city = user?.address?.city; // undefined if any step is null/undefined const result = arr?.[0]?.name; // works on arrays too const val = obj?.method?.(); // safe method call

Comparison table showing that ?? only fires for null and undefined, while || also fires for 0, empty string, and false

The yellow rows are where || silently replaces a valid value. If 0 is a meaningful count, || will replace it with your default. ?? will not.

One syntax trap worth memorizing: you cannot mix ?? with || or && without parentheses. JavaScript will throw a SyntaxError, which is at least honest compared to what it normally does.

// SyntaxError const x = a || b ?? c; // Fine const x = (a || b) ?? c;

Array Methods Worth Memorizing Cold

These are the ones that appear constantly. Know the return value of each without thinking.

// map: transform every element, returns new array (same length) const doubled = nums.map(n => n * 2); // filter: keep elements that pass the test, returns new array (shorter or same) const evens = nums.filter(n => n % 2 === 0); // reduce: accumulate to a single value const sum = nums.reduce((acc, n) => acc + n, 0); // find vs findIndex const item = arr.find(x => x.id === target); // returns the element or undefined const idx = arr.findIndex(x => x.id === target); // returns index or -1 // some / every const hasNeg = nums.some(n => n < 0); // true if any match const allPos = nums.every(n => n > 0); // true if all match // flat and flatMap const nested = [[1, 2], [3, 4]]; nested.flat(); // [1, 2, 3, 4], depth 1 nested.flat(Infinity); // flattens arbitrarily deep // flatMap: map then flatten one level (more efficient than .map().flat()) const sentences = ["hello world", "foo bar"]; sentences.flatMap(s => s.split(" ")); // ["hello", "world", "foo", "bar"]

The sorting trap is the one that bites nearly every engineer exactly once, usually in an interview. Array.prototype.sort converts elements to strings by default. [10, 9, 2].sort() returns [10, 2, 9] because "10" sorts before "2" lexicographically. JavaScript is not wrong here. It is just precisely correct about the wrong thing. Always pass a comparator.

nums.sort((a, b) => a - b); // ascending nums.sort((a, b) => b - a); // descending items.sort((a, b) => a.name.localeCompare(b.name)); // strings

Object Utilities That Interviewers Love to See

Object.entries, Object.keys, and Object.values let you treat objects like arrays when you need to iterate or transform them.

const freq = {}; for (const [key, count] of Object.entries(freq)) { /* ... */ } // Transform all values in an object cleanly const doubled = Object.fromEntries( Object.entries(scores).map(([k, v]) => [k, v * 2]) ); // Check if any value meets a condition Object.values(cache).some(v => v > threshold);

Object.fromEntries paired with Object.entries is the cleanest way to transform an object without mutation, and it reads clearly to the interviewer. No intermediate variables, no reassignment loops.


Map and Set: More Useful Than Your First Instinct

Plain objects work for most frequency maps, but Map wins in two specific situations: when keys are not strings, and when insertion order matters for your output.

// Map: any key type, has .size, iteration order is insertion order const map = new Map(); map.set([1, 2], "pair"); // array as key, works in Map, not in plain object map.size; // 1 // Frequency counter pattern const freq = new Map(); for (const c of s) freq.set(c, (freq.get(c) ?? 0) + 1); // Set for deduplication const unique = [...new Set(arr)]; // Set operations (ES2025, available in modern environments) const a = new Set([1, 2, 3]); const b = new Set([2, 3, 4]); a.intersection(b); // Set {2, 3} a.union(b); // Set {1, 2, 3, 4} a.difference(b); // Set {1}

One note on the new Set methods (intersection, union, difference): they are in ES2025 and not yet on LeetCode's Node 18 environment. Spread into arrays and use filter for those platforms.


String Methods That Save Lines

These come up more than people expect, especially in problems involving parsing or formatting.

// split and join are inverses "a,b,c".split(","); // ["a", "b", "c"] ["a", "b", "c"].join("-"); // "a-b-c" // Pad for fixed-width output "7".padStart(3, "0"); // "007" "hi".padEnd(5, "."); // "hi..." // Safe includes over indexOf str.includes("sub"); // true/false, clearer than indexOf !== -1 str.startsWith("pre"); str.endsWith("suf"); // repeat "ab".repeat(3); // "ababab" // Reverse a string. JavaScript has no built-in for this. // This three-step chain is the idiomatic answer. Everyone writes it the same way. const rev = str.split("").reverse().join("");

The Traps That Bite Under Pressure

JavaScript has a talent for being technically correct and completely unhelpful at the same time. These behaviors are genuinely surprising, well-documented, and somehow still get people every interview cycle.

// typeof null is "object" (a 1995 bug that cannot be fixed without breaking // the entire internet. It has outlived careers, companies, and entire // frontend frameworks.) typeof null === "object"; // true // In tree traversal: guard with === null, not typeof // NaN is not equal to itself NaN === NaN; // false Number.isNaN(NaN); // true (use this) isNaN("hello"); // true (global isNaN coerces, don't use it) // parseInt needs a radix parseInt("08"); // 0 in old engines (octal), 8 in modern parseInt("08", 10); // always 8, always explicit // Array.sort mutates in place const sorted = [...arr].sort((a, b) => a - b); // clone first if you need original // Object spread is shallow const a = { nested: { x: 1 } }; const b = { ...a }; b.nested.x = 99; a.nested.x; // also 99, shared reference

Number.isNaN is the correct check. The global isNaN coerces its argument to a number first, so isNaN("foo") returns true even though "foo" is a string, not NaN. The global version was a mistake. Number.isNaN was the correction. JavaScript ships both, forever, because compatibility.


Quick Reference

IdiomWhat It ReturnsCommon Trap
arr.find(fn)Element or undefinedNot the index
arr.findIndex(fn)Index or -1Not the element
arr.some(fn)BooleanStops at first match
arr.every(fn)BooleanStops at first failure
arr.flat(n)New arrayDefault depth is 1
arr.sort(cmp)Sorted in placeMutates original
??Right side if null/undefined`
?.undefined if chain breaksDoes not throw
structuredCloneDeep copyNot available pre-Node 17
Number.isNaNBooleanGlobal isNaN coerces first

Putting It Together in an Interview

These idioms matter most when you already know the approach and just need to write clean code fast. Reaching for flatMap instead of .map().flat(), or using ?? correctly instead of ||, signals fluency. The interviewer can see the difference in real time. So can you, once you're not spending mental budget remembering it.

The goal is zero cognitive load on the language itself, so you can spend all of it on the problem. If you want to practice this under actual interview conditions, SpaceComplexity runs realistic voice-based mock interviews where you get scored on fluency, communication, and correctness under time pressure. You write the code, you narrate it, you find out if the idioms are actually in muscle memory or just "pretty sure I remember."

For the broader question of which language to bring into interviews, see Best Language for Coding Interviews. For JavaScript-specific patterns and built-ins, see JavaScript for Coding Interviews. And if you're watching your interview time evaporate before you finish coding, the fix is usually covered in Coding Interview Mistakes.


Further Reading