Errors and Built-in Objects
This is where you learn how JavaScript signals and handles failure, plus the standard objects you reach for every day: Error types, JSON, regular expressions, dates and Intl, and the modern operators that tidy up defensive code. Interviewers use this area because it exposes whether you know the built-ins' sharp edges (silent JSON data loss, stateful regexes, 0-indexed months) rather than just their happy paths.
part ofJavaScriptoverview, primer and where to startread it →on this pageshowhide
explore
- Error Handling16 questions
- throw Semantics and Throwing Non-Errors4 questions
- try/catch/finally Control Flow4 questions
- Error Types and Custom Error Subclasses3 questions
- Error cause and Stack Traces5 questions
- JSON10 questions
- JSON.stringify and JSON.parse4 questions
- Replacer, Reviver, and JSON Edge Cases6 questions
- Regular Expressions15 questions
- Literals, Constructors, and Flags5 questions
- Groups, Backreferences, and Lookaround5 questions
- Matching and Replacing APIs5 questions
- Dates and Internationalization18 questions
- Date Pitfalls and UTC vs Local6 questions
- Temporal (Concept Level)6 questions
- Intl Formatting and Collation6 questions
- globalThis and structuredClone5 questions
questions
69 · 6 sectionsWhich built-in error constructors does JavaScript itself throw at runtime — TypeError, ReferenceError, RangeError, SyntaxError, URIError — and what kind of failure does each one signal?
basics
~20 sJavaScript throws TypeError when a value is the wrong kind of thing for the operation, ReferenceError when an identifier does not resolve, RangeError when a value of the right type is out of range, SyntaxError when source cannot be parsed, and URIError for malformed URI escapes.
In JavaScript, which values are legal after `throw`, and what concretely breaks in the catching code when a function throws the string 'Network unavailable' instead of `new Error('Network unavailable')`?
basics
~20 sJavaScript's throw accepts any value: strings, numbers, plain objects, null, even undefined. Only Error instances carry name, message and a stack, so a thrown string leaves the catch block with no diagnostics, err.message undefined, and err instanceof Error false.
In JavaScript, when does a `finally` block actually run? Does it still execute if the `try` block returns a value, or if an error is thrown that no `catch` clause handles?
basics
~20 sA JavaScript finally block runs on every exit from its try statement - normal completion, an early return, a break or continue, a caught error, and an error still propagating outward - which is exactly why cleanup belongs there.
In JavaScript, given `class ValidationError extends Error {}`, the expression `new ValidationError('bad email').name` evaluates to "Error" rather than "ValidationError". Why, and what does a correctly written custom error class set?
basics
~20 sThe name property is inherited from Error.prototype, whose value is the string Error; an empty subclass overrides nothing. A correct custom error calls super(message) and then assigns its own name, plus whatever structured fields callers need.
Inside a JavaScript catch block you decide the failure is not yours to handle. Compare `throw err;`, `throw new Error(err.message);`, and logging the error and returning — what does each leave the outer caller with?
basics
~20 sA bare throw err rethrows the identical object, so its type, custom properties and original stack all survive. throw new Error(err.message) starts a fresh error and discards them. Logging and returning is worst: the caller sees a successful call and a bogus value.
What does JSON.stringify() do with undefined, function values and symbols, and how does the outcome differ between an object property, an array element, and the top-level argument?
basics
~20 sJSON.stringify silently drops undefined, function and symbol object properties, turns those same values into null inside arrays, and returns the value undefined — not a string — when you pass one directly as the top-level argument.
What do JSON.stringify() and JSON.parse() each do in JavaScript, and how does the value returned by JSON.parse() relate to the object that was originally stringified?
basics
~20 sJSON.stringify() converts a JavaScript value into a string of JSON text; JSON.parse() turns such a string back into a JavaScript value. The result is a brand-new object graph that shares no references with the original.
JSON.stringify accepts a second argument called the replacer. What are its two valid forms, and what does each one do to the output?
basics
~20 sThe replacer is JSON.stringify's second argument. An array of keys acts as an allowlist that also fixes the output key order; a function is called for every key and value pair and returns the value to serialize, or undefined to omit that property.
How do you make JSON.stringify() produce indented, human-readable output, and what is the middle argument doing in a call like JSON.stringify(value, null, 2)?
basics
~10 sJSON.stringify's third parameter, space, controls indentation: pass a number of spaces or an indent string, as in JSON.stringify(value, null, 2). The null is the unused replacer slot sitting between the value and space.
Given const o = { m: new Map([['a', 1]]), s: new Set([1, 2]), n: NaN, i: Infinity }, what does JSON.stringify(o) produce — and what changes if you add a BigInt property?
basics
~20 sYou get '{"m":{},"s":{},"n":null,"i":null}'. Map and Set serialize as empty objects because their contents are internal rather than own properties, NaN and Infinity have no JSON literal so they become null, and adding a BigInt makes the call throw a TypeError.
In a JavaScript regular expression, what is the difference between (Mr|Ms) and (?:Mr|Ms), and when would you choose the non-capturing form?
basics
~20 sBoth parenthesis forms group a sub-pattern so quantifiers and alternation apply to the whole unit. Plain parentheses also capture, adding the matched text to the result array; (?: ... ) groups without capturing, so it never occupies a group number.
In JavaScript, what does String.prototype.replace do when you pass a plain string as the pattern, and how do replaceAll and a global regex differ from it?
basics
~20 sreplace() with a string pattern, or with a regex that lacks the g flag, substitutes only the first occurrence. Replacing every occurrence needs replaceAll() or a /g regex; replaceAll throws a TypeError if handed a non-global regex.
In JavaScript, what is the difference between writing a regular expression as the literal /\d+/ and as new RegExp("\\d+"), and when do you actually need the constructor?
basics
~20 sBoth produce the same RegExp. The literal is parsed as regex source, while the constructor takes an ordinary string, so every backslash must be doubled and a bad pattern fails at runtime. Use the constructor only for patterns assembled from runtime values.
Explain lookahead and lookbehind assertions in JavaScript regular expressions — what does "zero-width" mean, and give a case where a lookahead is the only clean solution.
basics
~20 sLookaround tests whether a sub-pattern matches at the current position without consuming characters, so the matched text excludes it. (?=x) and (?!x) look forward, (?<=x) and (?<!x) look backward, and each can be positive or negative.
A module declares `const RE = /^\d+$/g;` and a validate(value) function that returns RE.test(value). Callers report that the same valid value passes on one call and fails on the next. Why, and how do you fix it?
basics
~20 sA regex with the g flag carries mutable state: test and exec resume from its lastIndex property and advance it after each match, so a shared regex object alternates between matching and failing. Drop the g flag for a pure test, reset RE.lastIndex = 0, or build a fresh regex per call.
What does the JavaScript expression `new Date(2025, 0, 31)` represent, and which of the Date constructor's argument conventions most often cause off-by-one bugs?
basics
~20 snew Date(2025, 0, 31) is 31 January 2025 at local midnight. The month argument is zero-indexed (0 = January) while day-of-month starts at 1, and multi-argument construction is always read in the host's local time zone.
A JavaScript Date stores a single number. Given that, what do `getHours()` and `getTimezoneOffset()` actually return, and why can `toISOString()` show a different calendar day than `getDate()`?
basics
~20 sA Date holds only milliseconds since the epoch and carries no time zone. The plain getters project that instant into the host's local zone, the getUTC* getters project it into UTC, and getTimezoneOffset() returns UTC minus local in minutes — so it is negative east of Greenwich.
In JavaScript, why can `new Date('2025-03-15')` and `new Date('2025-03-15T00:00:00')` refer to two different instants, and what does that mean for parsing user input?
basics
~20 sA date-only ISO string is parsed as UTC midnight; the same date with a time part but no offset is parsed as local midnight. West of Greenwich the first therefore prints as the previous calendar day, which is the classic off-by-one-day date bug.
In JavaScript's Temporal API, what do Temporal.Instant, Temporal.PlainDateTime and Temporal.ZonedDateTime each model, and what extra information does converting between them require?
basics
~20 sTemporal.Instant is a fixed point on the global timeline with no zone or calendar. Temporal.PlainDateTime is a wall-clock reading with no zone, so it names no exact time. Temporal.ZonedDateTime is both together, carrying an IANA time-zone ID.
On a Temporal.ZonedDateTime, why can zdt.add({ days: 1 }) and zdt.add({ hours: 24 }) give different results, and how does Temporal resolve a wall-clock time that a DST transition erased?
basics
~20 sTemporal adds date units in calendar space and time units in exact-elapsed time, so across a DST shift one day may be 23 or 25 real hours. A wall-clock time that no longer exists is resolved by the disambiguation option, which defaults to compatible.
Optional Chaining, Nullish Coalescing, and Logical Assignment
all 5 Optional Chaining, Nullish Coalescing, and Logical Assignment questions →In JavaScript, what is the difference between `a ?? b` and `a || b`, and which left-hand values make the two produce different results?
basics
~20 sThe ?? operator falls back only when the left side is null or undefined; || falls back on any falsy value. So 0, -0, NaN, the empty string and false are kept by ?? but replaced by ||.
In JavaScript, what exactly does the optional chaining operator `?.` short-circuit, and in which situations does an expression containing `?.` still throw?
basics
~20 sOptional chaining short-circuits the whole remaining chain: if the value before ?. is null or undefined the entire expression evaluates to undefined, and later accesses, calls and their arguments are never evaluated. It only guards the link it is written on.
In JavaScript, how do the logical assignment operators `&&=`, `||=` and `??=` differ from writing `x = x && y`, and why does that difference matter for a property with a setter?
basics
~20 sLogical assignment short-circuits the assignment itself: when the test fails no write happens at all. So x ||= y writes only if x is falsy, x &&= y only if x is truthy, x ??= y only if x is null or undefined — and setters, proxy traps and frozen-object errors are skipped entirely.
Why is `const x = a ?? b || c;` a SyntaxError in JavaScript, and how do you express either intended grouping?
basics
~20 sJavaScript forbids combining ?? with || or && in one expression without parentheses, so the parser rejects it. Write (a ?? b) || c or a ?? (b || c) to state the grouping explicitly; the two mean different things.
A JavaScript service resolves options with `const retries = cfg.retries || 3` in dozens of places, and users report that explicit `0` and `false` settings are ignored. How do you audit and fix this, and where is `??` not the right replacement?
basics
~20 sTreat it as a semantics audit, not a find-and-replace: at each site decide which values mean absent. Numeric and boolean options should use ?? so 0 and false survive; string and array options where empty genuinely means missing need an explicit check, not ??.
What does structuredClone(value) give you that a JSON.parse(JSON.stringify(value)) round trip does not, and which values does it refuse to clone?
basics
~20 sstructuredClone performs a real deep copy: it preserves cycles and shared references and reproduces Date, RegExp, Map, Set, ArrayBuffer and typed arrays as themselves. It throws a DataCloneError for functions and symbols, and it does not preserve prototypes.
What is globalThis in JavaScript, and what problem does it solve that window, self, and global did not?
basics
~20 sglobalThis is the single standard name for the global object in every JavaScript environment. Browsers expose window, workers expose self, Node exposes global; globalThis, added in ES2020, resolves to the right one everywhere without feature sniffing.
What does top-level `this` evaluate to in a classic browser script, in an ES module, and in a Node CommonJS module, and why is `this` an unreliable way to reach the global object?
basics
~20 sTop-level this is the global object in a classic script, undefined in an ES module, and module.exports in a CommonJS module. Because the value depends on how the file is loaded, use globalThis when you actually want the global object.
You need a deep copy of an application state object that holds class instances, an options object with a callback in it, and a back-reference cycle. What happens if you call structuredClone on it, and how do you design around the parts it cannot handle?
basics
~20 sThe call throws a DataCloneError because of the callback, and it fails entirely rather than partially. The cycle would have been fine and the class instances would have survived as plain data without methods, so the fix is to separate cloneable state from behaviour and rehydrate explicitly.
What does the transfer option of structuredClone(value, { transfer }) do, and what state is the original ArrayBuffer left in afterwards?
basics
~20 sListing an ArrayBuffer in the transfer option moves its memory into the clone instead of copying it. The original buffer is left detached: its byteLength becomes 0 and it no longer holds any data, so nothing may read through it again.