AI InterviewSearch…Search problems, topics, or pages…Ctrl KGet started
Skip to content

16 Interview idioms / Checkpoint

Checkpoint — Interview idioms

26 min · +25 XP · 3 exercises · 12 questions

Exercises0/3
Quiz · 70% to clear12 q

This checkpoint closes the track. It covers the interview template and its JavaScript-specific decisions; the twelve algorithm patterns and their complexities; the idiom sheet and the trap behind each idiom; the reimplementation questions and the spec details they hinge on; and the theory repertoire in its two-sentence form.

How it works. Twelve questions and three programs; 70% on the questions and every program accepted clears the module — and with it the JavaScript study plan.

Before you start, make sure you can answer:

  • The six steps of the template and the choices to make before being asked (Map/Set, comparators, index-pointer queues, code points, BigInt, Array.from grids).
  • The signs that identify each pattern, its template shape, and the complexity of the whole solution including any sort.
  • The trap behind each idiom on the sheet: sort(), Math.max(...big), Array(n).map, reduce without a seed, s.length, parseInt in map, JSON round trips, Object.freeze.
  • The detail that decides each reimplementation: bind and new; map and holes; reduce and the empty array; Promise.all and order; then and microtasks/adoption; JSON.stringify and undefined/NaN/toJSON/cycles.
  • The two-sentence answers to the theory repertoire and where each goes deeper.

The programs are the three reimplementations senior rounds ask for most: a Promise class with chaining, adoption, catch/finally and the four static combinators, driven by a script and printing the real settlement order; a JSON.stringify that matches the native one on every listed case, including toJSON, replacers, indentation and cycle detection; and a deep-equality and deep-clone toolkit that handles NaN, Date, Map, Set, cycles and shared references, reported as a TAP log.

Common questions

What are the six steps for solving a coding interview problem?

Restate the problem, probe the edge cases and constraints, plan starting from the brute force and its complexity, code while explaining your intent, trace an example through the code, and analyse the time and space complexity.

Why does Array(3).map(fn) return empty slots?

Array(3) creates an array of three holes, and map skips holes, so the callback never runs and the result is still three empty slots. Array.from({ length: 3 }, (_, i) => i) creates and fills the array in one step.

Why do then callbacks always run asynchronously?

Promise handlers run as microtasks even when the promise has already settled, so the code after the then call always runs first and the order never depends on timing. A hand-written Promise that calls its handlers synchronously gets this wrong.

JavaScript Interview Practice Test: Coding and Theory Quiz

A JavaScript interview practice test: 12 questions on patterns, idioms and theory, plus a Promise class, JSON.stringify and deep equality to implement.

  • Course: JavaScript study plan
  • Module: Interview idioms
  • Kind: Checkpoint — cleared at 70%
  • Reading time: 26 min
  • Runtime: Node 16

Checkpoint — Interview idioms is the checkpoint that closes the Interview idioms module: a graded quiz and whole-program exercises, passed at 70%.

Instructions

This checkpoint closes the track. It covers the interview template and its JavaScript-specific decisions; the twelve algorithm patterns and their complexities; the idiom sheet and the trap behind each idiom; the reimplementation questions and the spec details they hinge on; and the theory repertoire in its two-sentence form.

How it works. Twelve questions and three programs; 70% on the questions and every program accepted clears the module — and with it the JavaScript study plan.

Before you start, make sure you can answer:

  • The six steps of the template and the choices to make before being asked (Map/Set, comparators, index-pointer queues, code points, BigInt, Array.from grids).
  • The signs that identify each pattern, its template shape, and the complexity of the whole solution including any sort.
  • The trap behind each idiom on the sheet: sort(), Math.max(...big), Array(n).map, reduce without a seed, s.length, parseInt in map, JSON round trips, Object.freeze.
  • The detail that decides each reimplementation: bind and new; map and holes; reduce and the empty array; Promise.all and order; then and microtasks/adoption; JSON.stringify and undefined/NaN/toJSON/cycles.
  • The two-sentence answers to the theory repertoire and where each goes deeper.

The programs are the three reimplementations senior rounds ask for most: a Promise class with chaining, adoption, catch/finally and the four static combinators, driven by a script and printing the real settlement order; a JSON.stringify that matches the native one on every listed case, including toJSON, replacers, indentation and cycle detection; and a deep-equality and deep-clone toolkit that handles NaN, Date, Map, Set, cycles and shared references, reported as a TAP log.

Common questions

What are the six steps for solving a coding interview problem?

Restate the problem, probe the edge cases and constraints, plan starting from the brute force and its complexity, code while explaining your intent, trace an example through the code, and analyse the time and space complexity.

Why does Array(3).map(fn) return empty slots?

Array(3) creates an array of three holes, and map skips holes, so the callback never runs and the result is still three empty slots. Array.from({ length: 3 }, (_, i) => i) creates and fills the array in one step.

Why do then callbacks always run asynchronously?

Promise handlers run as microtasks even when the promise has already settled, so the code after the then call always runs first and the order never depends on timing. A hand-written Promise that calls its handlers synchronously gets this wrong.

Exercises

A Promise from scratch

Implement MyPromise: one-shot settlement; then/catch/finally returning new promises; handlers always run asynchronously (queueMicrotask) even on a settled promise; missing handlers pass the value or reason through; a handler's return value resolves the next promise and a throw rejects it; thenables are adopted both when returned from a handler and when passed to resolve (another MyPromise, a plain { then } object, or a native Promise); an executor that throws rejects. Statics: resolve, reject, all (input order, fail-fast, [] resolves at once), allSettled, race and any (AggregateError when every input rejects, including an empty input). The starter's scenarios — chain adopt reject order all allSettled race any, chosen by stdin — drive it and print [<scenario>] <message> lines.

Example (order) →

[order] sync 1
[order] sync 2 (then already registered)
[order] then on a settled promise
[order] queueMicrotask registered after

The then on an already-fulfilled promise still ran after the synchronous code — and before a microtask queued later.

JSON.stringify from scratch

Write stringify(value, replacer, indent) matching the native one. Each input line is <expression> | <replacer expression or -> | <indent expression or -> (the starter evaluates them); print mine=<result> match=<bool> — or throws <ErrorName> match=<bool> when yours throws — comparing against JSON.stringify. The details: toJSON is applied first (Dates), then a replacer function (called with this = the holder); an array replacer is an allow-list applied in its order at every level; undefined, functions and symbols are omitted from objects and become null in arrays; NaN/±Infinity become null; boxed primitives unwrap; BigInt and cycles throw TypeError; strings are escaped (", \, control characters as \b \f \n \r \t or \u00XX); a numeric indent is capped at 10 spaces and a string indent at 10 characters, with ": " after keys only when indenting; empty containers print {}/[].

Example: {a: 1, b: 2, c: {a: 3, b: 4}} | ["c", "a"] | - → mine={"c":{"a":3},"a":1} match=true; a self-referencing object → throws TypeError match=true.

A deep-equality and deep-clone toolkit

Implement deepEqual(a, b) (Object.is for primitives so NaN equals NaN and 0 differs from -0; same prototype; Date by time; RegExp by source and flags; Map/Set by entries; arrays by elements; objects by own keys; cycles via a seen-map), deepClone(value) (primitives, Date, RegExp, Map, Set, arrays and objects keeping their prototype; a WeakMap of clones so cycles and shared references survive), and flatten/unflatten with dotted keys where arrays and empty objects are leaves. Commands: equal <expected> ||| <a> ||| <b>, clone <expr> (checks equality, distinctness, a self cycle, x/y shared references and per-key prototypes), flatten <expr> (prints the flat JSON and checks the round trip). Output is TAP: ok <n> - … / not ok <n> - …, then 1..<n> and # pass <p> fail <f>.

Example: clone (() => { const shared = { v: 1 }; const o = { x: shared, y: shared, when: new Date(0), tags: new Set([1]) }; o.self = o; return o; })() → ok 7 - clone: equal=true distinct=true cycle=kept shared=kept typesKept=true; flatten {a: {b: {c: 1}, d: [1, 2]}, e: "x", f: {}} → ok 9 - flatten {"a.b.c":1,"a.d":[1,2],"e":"x","f":{}} roundtrip=true.

In this module: Interview idioms

← Theory drill — the questions, the two-sentence answers, and where each one goes deeper