JavaScript interview bank

Questions interviewers actually ask, each answered at the length you would say it aloud, with the topic to reread if you were not sure.

91 questions Junior Senior
All levels Junior Mid Senior
Reveal one by one Show all answers
Report an error

Core language

48 questions
01 How do ===, Object.is, and SameValueZero differ, and where does the choice matter? Mid common reveal ▾ hide ▴

Use === for ordinary strict comparison: it performs no type coercion, treats NaN as unequal to itself, and treats 0 and -0 as equal. Object.is changes only those numeric edges: NaN equals itself, while 0 and -0 differ. SameValueZero treats NaN as equal and the two zeros as equal; Array.prototype.includes and Map and Set key matching use it. The boundary matters when deduplicating numeric data, detecting state changes, or searching for NaN. For example, includes finds NaN but indexOf, which uses strict equality, does not.

Was this clear?
02 How does JavaScript property lookup use the prototype chain, and how do you test ownership safely? Mid common reveal ▾ hide ▴

A read first checks the object itself, then follows its internal prototype link until it finds the key or reaches null. An own property can shadow an inherited one, including an accessor. The in operator reports either own or inherited properties, so it is not an ownership test. Use Object.hasOwn(object, key), especially for objects that may have a null prototype or an overridden hasOwnProperty method. At an input boundary, also remember that assignment can trigger inherited setters. If arbitrary keys are accepted, use deliberate allowlists or a null-prototype dictionary.

Was this clear?
03 Why are JavaScript private fields different from properties whose names start with an underscore? Senior occasional reveal ▾ hide ▴

A #name is a lexically declared private element, not a string-keyed property. Code outside the declaring class cannot name it, reflection and JSON serialization do not enumerate it, and access performs a brand check on the receiver. A subclass does not inherit direct access to the parent private name, and a Proxy wrapper is not automatically branded as the target. By contrast, _name is only a convention and remains readable, writable, and enumerable according to its descriptor. Expose behavior through public methods, and do not confuse language privacy with authorization or encryption.

Was this clear?
04 What guarantees do copying array methods provide compared with mutating methods? Junior common reveal ▾ hide ▴

Mutating methods such as sort, reverse, and splice change the receiver. Their copying counterparts toSorted, toReversed, and toSpliced return a different outer array and leave the receiver unchanged. That guarantee is shallow: element objects are still shared, so changing a nested object is visible through both arrays. Return values also differ across mutators, so never infer them from the mutation. For example, sort returns its receiver, while splice returns removed elements. In state-oriented code, trace both outer-array identity and nested identity before claiming an update is immutable.

read more Array methods
Was this clear?
05 What does it mean that ES module imports are live bindings, and why can a cycle still fail? Senior occasional reveal ▾ hide ▴

An ES module import is a read-only view of the exporter binding, not a copied snapshot. When the exporting module later updates a let binding, importers observe the new value, but they cannot assign through the import name. Before evaluation, the loader links the module graph, which permits many cycles. A cycle still fails when top-level evaluation reads a lexical export before its module has initialized that binding, producing a temporal-dead-zone error or order-sensitive behavior. Break the cycle, defer the read into a function, or move shared contracts into a lower-level module.

read more Modules
Was this clear?
06 What contracts make an object iterable, and how is early-loop cleanup performed? Mid occasional reveal ▾ hide ▴

An iterable provides Symbol.iterator, which returns an iterator. Each next call returns an object with done and, when relevant, value. The iterable and iterator may be the same object, but they need not be. When for…of exits early because of break, return, or an abrupt completion, it performs iterator closing by calling the iterator return method when present. A generator uses that path to run finally cleanup. This does not make every manually consumed iterator self-cleaning: code that calls next directly must also define and honor an ownership and closing policy.

Was this clear?
39 Why does forEach not wait for an async callback, and which alternatives express completion? Junior common reveal ▾ hide ▴

In Node 24, forEach() invokes each callback synchronously and ignores its return value, so Promises returned by an async callback are neither collected nor awaited. The outer function can finish while work and rejections remain unowned. Use await Promise.all(items.map(worker)) when all operations may run concurrently and every result must settle, or for...of with await when order or capacity requires sequential work. For large inputs, use an explicit bounded worker pool; unbounded Promise.all() can overload a dependency even though completion is correctly observed.

Was this clear?
40 How do array methods treat holes, and why can spreading a sparse array change later behavior? Mid occasional reveal ▾ hide ▴

In Node 24, many iterative methods, including map(), filter(), and forEach(), skip indexes that have no property, while for...of and the array iterator produce undefined for those positions. map() preserves the holes in its result; spreading the array materializes them as actual undefined elements, so a later callback now visits them. This difference matters for counts, validation, and serialization. Do not use holes to represent domain state. Normalize deliberately, or test membership with index in array when a distinction between an absent slot and a stored undefined is required.

read more Array methods
Was this clear?
51 What does const make immutable, and how should object ownership be reviewed separately? Junior common reveal ▾ hide ▴

In Node 24, const prevents reassignment of one lexical binding; it does not freeze the object referenced by that binding. Properties and nested objects may still change, and aliases observe the same mutations. Object.freeze() restricts only the target object’s own layer, so nested references and accessor side effects can remain mutable. Review binding stability and data ownership as separate questions. If callers need a snapshot, construct new objects at the levels whose identity must differ and test nested identity. Blind deep freezing can mishandle cycles, class instances, proxies, and resources, so it also needs an explicit contract.

Was this clear?
52 Why is a truthiness check not a presence or validation check? Junior occasional reveal ▾ hide ▴

In Node 24, conditions convert values to Boolean, making 0, -0, 0n, NaN, false, the empty string, null, and undefined falsy. Empty arrays, empty objects, and strings such as "false" are truthy. Therefore if (value) cannot say whether a field exists, an array has items, or text represents a Boolean. Use ?? when only null and undefined mean missing, Object.hasOwn() when property presence matters, and domain validation for type, syntax, and range. Using || as a default can silently replace valid zero, false, or empty-string values.

Was this clear?
53 How do let, const, and var differ before their declaration executes? Junior common reveal ▾ hide ▴

In Node 24, let and const create block-scoped bindings when the scope is entered, but those bindings remain uninitialized in the temporal dead zone until their declarations execute. Reading either early throws ReferenceError; const must also receive an initializer and cannot later be reassigned. var is function- or global-scoped and is initialized to undefined during scope setup, so an early read succeeds with undefined and can hide an ordering defect. Hoisting does not mean declarations move in source. Prefer lexical declarations, order initialization explicitly, and inspect module cycles when an apparently declared export is still uninitialized.

Was this clear?
54 Which date strings are safe to accept, and how do you detect an invalid Date? Mid common reveal ▾ hide ▴

In Node 24, the specified date-time format is the portable baseline: Z means UTC, an explicit offset identifies an instant, a date-only form is interpreted as UTC, and a date-time without an offset is local. Other human-shaped strings may be implementation-defined, and even plausible components can normalize rather than fail. Define one grammar and zone policy at the boundary, then check Number.isNaN(date.getTime()); a Date object is truthy even when invalid. Do not call toISOString() before validation because it throws RangeError, and do not use regex alone to prove a calendar date exists.

read more Date
Was this clear?
55 Why is adding 86,400,000 milliseconds not always the same as adding one calendar day? Senior occasional reveal ▾ hide ▴

In Node 24, adding 86_400_000 advances an instant by exactly 24 elapsed hours. A local calendar day can span 23 or 25 hours across a daylight-saving transition, so “same local time tomorrow” is a different requirement. Date stores only an instant, not a named time zone or recurrence rule. Choose elapsed arithmetic for expiry durations; for calendar recurrence, retain the wall-clock fields and IANA zone, then define gap and overlap behavior. Local setters use the host zone and mutate the receiver, so copy first and test both sides of the relevant transition.

read more Date
Was this clear?
56 What happens when Date values cross a JSON boundary, including an invalid Date? Mid common reveal ▾ hide ▴

In Node 24, JSON has no date scalar. JSON.stringify() calls a valid Date object’s toJSON(), which yields a UTC ISO string; parsing that text later returns a string, not a reconstructed Date. For an invalid date, toJSON() returns null, although calling toISOString() directly would throw RangeError. This silent type change can hide bad input. Validate getTime() before serialization, document whether the wire field is a canonical instant string or epoch milliseconds, and revive only schema-named fields. Broadly converting every date-shaped string can corrupt identifiers and calendar-only values.

read more Date JSON
Was this clear?
57 What does successful JSON.parse prove, and what must happen before the value is trusted? Junior common reveal ▾ hide ▴

In Node 24, JSON.parse() proves that the complete input follows JSON grammar; it may still return null, a primitive, an array, or an object missing required fields. Parsing does not establish schema validity, business invariants, or authorization. After catching syntax errors, validate the top-level category, property ownership, every nested type, ranges, and allowed values, then construct a domain object from an allowlist. Do not catch every failure and return {}, because malformed input then looks like legitimate empty data. Keep syntax, validation, and permission failures distinct so callers and logs preserve the real boundary that failed.

read more JSON
Was this clear?
58 How should a JSON contract carry integers larger than Number can represent exactly? Mid occasional reveal ▾ hide ▴

In Node 24, JSON number syntax can contain an integer whose parsed JavaScript Number has already lost precision. Converting that rounded value with BigInt(value) cannot restore the original digits, and JSON.stringify() throws on a raw BigInt. The portable contract is a validated decimal string with an explicit field meaning, converted to BigInt only after syntax and range checks. Node 24 also supplies reviver source context for primitive values, so a schema-known field can read context.source, but that is a runtime-specific boundary. Test maximum values and cross-language producers; never improvise with generic stringify equality.

read more JSON
Was this clear?
59 How do defaults at different levels of a destructuring pattern behave? Mid common reveal ▾ hide ▴

In Node 24, a destructuring default runs only when the value extracted at that exact pattern position is undefined. In function read({ profile: { name = 'guest' } = {} } = {}), the parameter default protects an omitted outer argument, the profile default protects an undefined property, and the leaf default protects an undefined name. None replaces explicit null. Validate untrusted shapes before a dense pattern, or normalize a deliberately nullish outer value with ??. A common pitfall is assuming the leaf default protects a missing intermediate object; evaluation fails before the leaf is reached.

Was this clear?
60 Why is object rest unsafe as a redaction boundary, and what exactly does it copy? Mid occasional reveal ▾ hide ▴

In Node 24, object rest creates a new ordinary object and copies the remaining own enumerable string and Symbol properties. It excludes inherited and non-enumerable properties, invokes getters while reading, converts accessors to data values, and shares nested object references. Code such as { password, ...publicUser } is a denylist: a newly added token or secret leaks automatically. Build logs and responses from an explicit allowlist of public fields, then decide how deeply each nested value must be copied. Object rest is useful when unknown fields should be retained, not when unknown fields must stay private.

Was this clear?
61 How does array destructuring consume and close an iterator? Mid common reveal ▾ hide ▴

In Node 24, an array pattern uses the iterable protocol rather than requiring an Array. Each position requests next(), and an elision still consumes and discards one iterator result. If the pattern ends before the iterator, iterator closing calls return() when present. A rest element eagerly consumes every remaining value into a new array, so it can exhaust memory or never finish on an unbounded source. Test custom iterables by counting next() and return() calls. When each read is expensive or requires acknowledgment, explicit iteration is clearer than a compact pattern and gives cleanup ownership a visible place.

Was this clear?
62 Why does compiling modern JavaScript syntax not prove the deployed module will run? Mid common reveal ▾ hide ▴

In the Node 24 baseline, compatibility has separate parser, transform, runtime, and host layers. A compiler can rewrite syntax such as arrows or optional chaining yet leave calls to missing built-ins, and it cannot make browser DOM APIs exist in Node. Module specifier resolution also belongs to the host: a bundler alias or extensionless import may fail in native execution. Define the deployed runtime and artifact first, then test that artifact in Node 24. Add polyfills only for required runtime APIs, verify transforms preserve semantics such as iterator closing, and do not treat a successful source build as an end-to-end compatibility result.

Was this clear?
63 What values travel through yield, next, return, and throw in a generator? Senior common reveal ▾ hide ▴

In Node 24, calling a generator function creates a suspended iterator without running its body. The first next(value) starts execution, but its argument is ignored because no yield is waiting. A later next(value) makes the previously suspended yield expression evaluate to that value. iterator.return(value) requests completion and lets finally run, while iterator.throw(error) injects an exception at the suspension point. A generator’s final return value has done: true and is not collected by for...of or spread. Two-way generators are compact but easy to misuse; prefer named methods when message order is a business protocol.

Was this clear?
64 How should an application safely select a module with dynamic import? Senior common reveal ▾ hide ▴

In Node 24, import() evaluates a specifier under host resolution rules and returns a Promise for the module namespace. Letting outside input build that specifier widens the resolution surface and can hide targets from a bundler. Map public names to fixed loader functions, reject unknown names, and require every target to expose the same documented shape. Catch resolution and evaluation rejection at the await import() boundary, separately from failures in the exported business call. Avoid timestamp query strings as cache busting: distinct resolved URLs create distinct module identities, repeat top-level side effects, and can grow retained module state.

read more Modules
Was this clear?
65 Why can try...catch miss a rejection from an async function call? Mid common reveal ▾ hide ▴

In Node 24, calling an async function returns a Promise immediately. If the call is made inside try without await, a later rejection belongs to that Promise after synchronous control has left the block, so the surrounding catch does not receive it. Await the operation inside the policy boundary, return the Promise to an owning caller, or attach an intentional terminal rejection handler for background work. A throw inside an async function rejects its Promise even before the first await. The pitfall is starting work without assigning ownership for rejection, cancellation, shutdown, and observability.

Was this clear?
66 How can finally accidentally replace a return value or error? Senior occasional reveal ▾ hide ▴

In Node 24, finally runs before control leaves try or catch, including return and throw paths. If finally itself returns or throws, that new completion replaces the pending one, so a valid result or original failure can disappear. Keep finally focused on idempotent cleanup and let it complete normally. If cleanup can fail, define deliberately whether the primary error, cleanup error, or an aggregate crosses the boundary; do not accept accidental precedence. Also remember that finally is not a process-shutdown guarantee, so durable recovery cannot rely solely on JavaScript cleanup executing.

Was this clear?
67 How do you distinguish a missing Map key from a key storing undefined? Mid common reveal ▾ hide ▴

In Node 24, map.get(key) returns undefined both when the key is absent and when the key explicitly stores undefined. Use map.has(key) when presence itself is meaningful, then read the value. get(key) || fallback is even broader: it replaces stored 0, false, and empty strings. ?? preserves those falsy values but still cannot distinguish absence from stored undefined. Define the value domain before selecting a check. For a counter where undefined is not valid, (counts.get(key) ?? 0) + 1 is clear; for tri-state data, branch on has() explicitly.

read more Map and Set
Was this clear?
68 Why does Set not deduplicate objects with equal fields, and what should you use instead? Mid occasional reveal ▾ hide ▴

In Node 24, Set members and Map keys use SameValueZero. Primitive edge cases include one NaN and one zero, but objects compare by identity, so two separate { id: 7 } objects remain two members. If business identity is id, key a Map by that stable value and decide whether the first or last record wins. A serialized object is not a safe generic key unless canonicalization rules cover property order, unsupported values, and collisions. The trade-off is explicit normalization work, but it makes deduplication semantics testable instead of depending on reference reuse by accident.

read more Map and Set
Was this clear?
69 How do floor, ceil, trunc, and round differ for negative values? Mid common reveal ▾ hide ▴

In Node 24, Math.floor() rounds toward negative infinity, ceil() toward positive infinity, and trunc() toward zero. Math.round() chooses the nearest integer, with an exact midpoint toward positive infinity, so Math.round(-2.5) is -2; Math.round(-0.5) can produce negative zero. These rules are not financial or banker’s rounding. Name the required direction or midpoint policy before choosing an API, and test positive and negative fractions plus -0. Avoid value | 0 or ~~value: those coerce to signed 32-bit integers and can wrap large or non-finite inputs.

read more Math object
Was this clear?
70 Why is Number.EPSILON not a universal tolerance for floating-point comparisons? Senior occasional reveal ▾ hide ▴

In Node 24, Number.EPSILON is the distance from 1 to the next larger representable Number. It does not describe measurement noise or rounding error at every magnitude. A fixed epsilon can be far too strict for large values and inappropriate near zero. Derive absolute and relative tolerances from the domain error budget, often accepting when |a-b| is below an absolute floor or a relative fraction of the larger magnitude. Continue using exact equality for discrete counts and identifiers. A pitfall is replacing all comparisons with approximate ones, which can blur a real business threshold.

read more Math object
Was this clear?
71 When is Math.random the wrong random source? Mid common reveal ▾ hide ▴

In Node 24, Math.random() returns an approximately uniform Number in [0, 1), exposes no standard seed, and has no cryptographic-strength guarantee. It fits visual variation and ordinary non-security sampling, but not reset tokens, verification codes, session identifiers, or reproducible simulations. Use Web Crypto or a reviewed high-level API for security; mapping secure bytes to an arbitrary range must still avoid modulo bias. For tests and simulations, inject a seeded pseudorandom source and record its seed. Also define empty ranges and inclusive endpoints before mapping values, or an index formula can produce biased or invalid output.

read more Math object
Was this clear?
72 When does WeakMap help memory ownership, and why does it not replace cleanup? Mid common reveal ▾ hide ▴

In Node 24, a WeakMap does not keep its object or non-registered-Symbol keys reachable solely through the collection. It fits metadata whose lifetime should follow an object already owned elsewhere. It does not weaken references from listeners, timers, arrays, closures, or other caches, and it never closes a socket or unsubscribes a handler. Use an explicit, preferably idempotent close(), unsubscribe function, or abort signal for resources. A common trade-off is observability: WeakMap has no iteration, size, or deterministic eviction signal, so use Map with a bounded policy when metrics or enumeration are required.

Was this clear?
73 Why do WeakMap and WeakSet omit size and iteration? Mid occasional reveal ▾ hide ▴

In Node 24, weak entries may disappear after their keys become unreachable, but garbage-collection timing is deliberately unspecified. Exposing size, keys, or iteration would make application behavior observe memory pressure and collection scheduling, and enumeration could itself make keys reachable again. Weak collections therefore support only identity-based query and deletion through keys the caller already holds. They are unsuitable for dashboards, serialization, capacity limits, or deterministic expiry. Use an ordinary Map or Set with explicit eviction for those jobs. Never maintain a parallel strong key list to make a WeakMap enumerable, because that list cancels the weak-lifetime benefit.

Was this clear?
74 Which values can be weak keys in Node 24, and how are they matched? Senior common reveal ▾ hide ▴

In Node 24, WeakMap keys and WeakSet members must be garbage-collectable objects or non-registered Symbols. Strings, numbers, and registered values from Symbol.for() are ineligible and cause TypeError; boxing a string merely creates a temporary object with the wrong lookup identity. Matching uses object or Symbol identity, not fields or descriptions, so reconstructing { id } will not hit an entry stored under an earlier object. If callers identify data by a stable string or number, use Map. Choose a weak collection only when callers already carry the canonical object and metadata should share its lifetime.

Was this clear?
75 How do Object.defineProperty defaults differ from ordinary assignment? Mid common reveal ▾ hide ▴

In Node 24, an object-literal property or ordinary assignment normally creates a writable, enumerable, configurable data property. Object.defineProperty(target, key, { value }) defaults every omitted Boolean descriptor flag to false, producing a non-writable, non-enumerable, non-configurable property. Later writes may throw in strict mode, and enumeration or deletion can appear to ignore the property. Spell out every flag the contract depends on and inspect it with Object.getOwnPropertyDescriptor(). Making a property non-configurable is largely one-way, so do not apply it before confirming that later initialization, testing, or migration will not need redefinition.

Was this clear?
76 What does Object.assign lose or execute when copying an object? Senior occasional reveal ▾ hide ▴

In Node 24, Object.assign() reads enumerable own string and Symbol keys from each source and writes their current values to the target from left to right. Reading runs source getters, writing can run target setters, later sources overwrite earlier ones, and the target is mutated. The operation does not preserve source descriptors or prototype and copies nested object references only. Use Object.getOwnPropertyDescriptors() with Object.create() when descriptor behavior and prototype must survive. For untrusted input, do not assign arbitrary keys into a privileged ordinary object; construct an allowlisted record or a deliberate null-prototype dictionary.

Was this clear?
77 Why can an empty Proxy break a method that accesses a private field? Senior common reveal ▾ hide ▴

In Node 24, a proxy is a distinct receiver and does not inherit the target’s private brand or built-in internal slots. Calling proxy.method() can find the target’s method, but the call supplies the proxy as this; this.#field then throws TypeError. The same issue affects branded built-ins such as Map methods. An empty handler is therefore not transparent for every object. Prefer an explicit adapter. Binding selected methods to the target can work, but it changes function identity, fluent return behavior, and whether the target escapes, so test every exposed method, getter, setter, and callback path.

Was this clear?
78 How should a class with private fields define copying and serialization? Mid common reveal ▾ hide ▴

In Node 24, private elements are not ordinary properties, so object spread, Object.assign(), reflection, structuredClone(), and default JSON serialization do not reproduce a class’s private brand and state. Freezing the instance also does not prevent class methods from changing private fields. Define a public data projection or toJSON() containing only intended fields, validate it at the boundary, and provide a constructor or static factory that restores invariants. A getter that returns a private mutable array directly still leaks its reference; return the required projection or copy depth instead of treating the # name as complete encapsulation.

Was this clear?
79 Which proxy invariant failures often appear only after a target is frozen or made non-extensible? Senior common reveal ▾ hide ▴

In Node 24, proxy traps cannot report an object shape that contradicts protected target facts. ownKeys cannot return duplicates, omit a non-configurable own key, or add keys for a non-extensible target. A get trap cannot invent a different value for a non-writable, non-configurable data property, and write-related traps face corresponding restrictions. Violations throw TypeError, even if loose tests passed on an extensible target. Start with the matching Reflect result and transform minimally. Test non-configurable properties, getter-only accessors, and Object.preventExtensions(); treating these exceptions as caller errors hides a broken handler contract.

Was this clear?
80 Why is one proxy trap rarely enough to enforce an object policy? Senior occasional reveal ▾ hide ▴

In Node 24, fundamental operations have separate traps. A set validator does not intercept Object.defineProperty(), and hiding a key in get does not automatically hide it from in, Reflect.ownKeys(), descriptors, or deletion. A policy implemented in only one trap can therefore be bypassed or return contradictory observations. Build an operation matrix from actual caller capabilities, decide which operations forward or reject, and use the matching Reflect method with the original receiver. Proxy is also a poor security boundary when callers retain the target or can perform an uncovered operation; prefer a narrow explicit API for authorization.

Was this clear?
81 How do Symbol(), Symbol.for(), and a well-known Symbol differ in identity and ownership? Mid occasional reveal ▾ hide ▴

In Node 24, every Symbol(description) call creates a new non-registered identity; equal descriptions do not make symbols equal. Symbol.for(key) reuses an identity from the runtime-wide registry, and Symbol.keyFor() reports only registered keys. Well-known values such as Symbol.iterator are fixed protocol keys defined by the language. Export one ordinary Symbol when a package owns an extension key; use the registry only for an intentional, namespaced runtime convention. Registry identity does not cross JSON, processes, or persistence, and any code knowing the key can retrieve it, so it is neither secret storage nor a durable identifier.

read more Symbol
Was this clear?
82 Which object operations include Symbol keys, and why are they not private? Mid common reveal ▾ hide ▴

In Node 24, Object.keys() and for...in exclude Symbol keys, while Object.getOwnPropertySymbols() and Reflect.ownKeys() reveal them. Object spread and Object.assign() copy enumerable own Symbol keys, but default JSON serialization omits them. Enumerability and key type are separate axes, so low visibility in one operation is not access control. A caller holding the Symbol can read the property, and reflection can discover unknown Symbols. Use Symbols to avoid extension-key collisions; use private fields or closure state for language-level encapsulation. At boundaries, define the exact key-selection matrix instead of assuming copying and validation inspect the same properties.

Was this clear?
83 What does defining Symbol.iterator promise to JavaScript consumers? Senior common reveal ▾ hide ▴

In Node 24, syntax such as for...of, array spread, and Array.from() looks up the well-known Symbol.iterator method and expects it to return an iterator whose next() yields result objects. Returning an array directly is not enough; the returned object must implement the iterator contract. If traversal should be repeatable, each method call should create independent cursor state. Early consumer exit may invoke the iterator’s return() for cleanup. A well-known Symbol prevents naming collisions but does not validate behavior. Test two concurrent traversals, early break, thrown consumer code, and materialization bounds, especially for resource-backed or infinite sequences.

Was this clear?
84 When do string length and regular-expression matches fail to represent user-visible characters? Mid common reveal ▾ hide ▴

In Node 24, string length and method indexes count UTF-16 code units. A u or v regular expression can make many operations code-point-aware, and Unicode property escapes classify code points, but one visible grapheme may still contain several code points joined by combining marks or zero-width joiners. Therefore slice(0, 1) can split a surrogate pair, while /^.$/u can still reject one visible emoji sequence. State whether a limit uses bytes, code units, code points, or grapheme clusters. Use Intl.Segmenter for interface characters and test combining marks and joined emoji; use protocol-defined units for wire formats.

Was this clear?
85 How do you insert untrusted replacement text literally with replace or replaceAll? Mid common reveal ▾ hide ▴

In Node 24, a string replacement value has its own syntax: $& means the full match, $1 and $<name> select captures, and $$ produces a dollar sign. Passing user data directly as that string can therefore interpolate matched text instead of inserting the supplied bytes literally. Pass a replacer function such as text.replace(pattern, () => replacement); its return value is not interpreted again for dollar tokens. Separately choose first-versus-all behavior and fixed text versus regex. Escape dynamic search text with RegExp.escape() only when it should be literal, and test $&, $1, and repeated dollar signs.

Was this clear?
86 Why can repeated test calls on the same global or sticky RegExp alternate results? Senior occasional reveal ▾ hide ▴

In Node 24, test() and exec() on a RegExp with g or y start from mutable lastIndex. A successful match advances it to the match end, while failure resets it to zero. Reusing one module-level matcher therefore makes a Boolean test depend on earlier calls or another asynchronous operation. Remove g when only existence matters, create a fresh expression per independent operation, or give one scanner explicit ownership and initialize lastIndex. Sticky y additionally requires a match exactly at that index. Tests should repeat the same input and interleave two inputs to expose accidental shared state.

Was this clear?
87 When is lowercasing both strings the wrong way to compare user-visible text? Senior occasional reveal ▾ hide ▴

In Node 24, toLowerCase() performs Unicode case conversion but does not express a locale’s complete search or sort rules, canonical equivalence, or identifier-security policy. For user-visible comparison, configure one Intl.Collator with the intended locale and sensitivity, then interpret compare() only as negative, zero, or positive; exact return magnitudes are not guaranteed. Protocol identifiers may instead require ASCII case folding or exact code-unit equality. Do not reuse display-locale collation for authorization keys. Test the target languages and normalization forms, because a pleasant UI comparison can intentionally consider strings equal that a security boundary must keep distinct.

Was this clear?
88 Which typed-array operations share bytes, and which create independent storage? Mid common reveal ▾ hide ▴

In Node 24, view.subarray() creates another window over the same backing buffer, while view.slice() allocates and copies selected elements. Constructing a typed array from another view converts and copies element values; constructing one from view.buffer, an offset, and a length reinterprets shared bytes. These forms can look interchangeable but define different ownership. If a callee retains data after the call, copy or transfer according to the lifecycle; a borrowed shared view lets later caller writes change the result. Test mutation in both directions and preserve byteOffset and byteLength, especially for pooled Node Buffer windows.

Was this clear?
89 Why should a binary parser use DataView with an explicit byte order and exact window? Senior common reveal ▾ hide ▴

In Node 24, multibyte typed arrays use the runtime’s native byte order, while DataView reads and writes each field with an explicit littleEndian argument; omitted or false means big-endian. A parser receiving a Uint8Array or Buffer must also preserve its local window with new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength). Using only bytes.buffer can expose unrelated pooled bytes. Check remaining length before every field read, then validate signedness and business range. Fixed byte fixtures from the protocol catch endianness mistakes better than an encoder-decoder round trip that may share the same wrong assumption.

Was this clear?
90 What happens to typed-array views when an ArrayBuffer is resized or transferred? Senior occasional reveal ▾ hide ▴

In Node 24, an ArrayBuffer created with maxByteLength can resize. A length-tracking view follows available storage, while a fixed-length view becomes wholly out of bounds if shrinking makes its declared range no longer fit; it may report length zero and later return in bounds after growth, but discarded bytes do not return. transfer() creates destination storage and detaches the source, invalidating all old views. Give resizing or transfer one clear owner and treat old references as consumed. A variable remaining in scope does not prove accessible bytes, so test asynchronous handoff, shrink boundaries, and every method used after invalidation.

Was this clear?

Functions and scope

17 questions
07 How is this selected for an ordinary JavaScript function? Junior common reveal ▾ hide ▴

For an ordinary function, this is primarily chosen by the call form, not where the function was defined. new creates a receiver and has the strongest relevant binding; call, apply, or a bound function supplies an explicit receiver; object.method() uses the base object; a plain strict-mode call receives undefined. Extracting const f = object.method therefore loses the implicit receiver. Fix the boundary by calling through the object, using a wrapper, or binding once. Binding creates a new function identity, so retain it when an API later needs the same callback for removal.

read more this binding
Was this clear?
08 When is an arrow function the wrong replacement for an ordinary function? Mid common reveal ▾ hide ▴

An arrow function is wrong when the API expects a dynamic receiver, construction with new, its own arguments object, or generator behavior. Arrows lexically capture this, arguments, super, and new.target from the surrounding context; call, apply, and bind cannot replace that captured this. This makes arrows useful for callbacks that should preserve an enclosing method receiver, but poor as prototype methods that must operate on the object before the dot. Also distinguish expression bodies from block bodies: returning an object literal implicitly requires parentheses, otherwise braces are parsed as a block.

Was this clear?
09 What does a closure retain, and how can that both preserve state and retain memory? Mid common reveal ▾ hide ▴

A closure retains access to lexical bindings from the environment where the function was created; it does not freeze copies of their current values. Reassigning a captured let is visible to later calls, while separate factory calls normally create separate environments. Memory follows reachability: if a long-lived listener retains the closure, captured objects can remain reachable too. A reference cycle alone is not a leak once the whole cycle is unreachable. Keep the exact listener identity, provide unsubscribe or dispose, and capture only the state the callback actually needs.

Was this clear?
10 How do call, apply, and bind differ, including when the bound function is constructed? Senior occasional reveal ▾ hide ▴

call invokes immediately with arguments listed separately; apply invokes immediately with arguments supplied from an array-like value; bind does not invoke and instead returns a new function with a fixed receiver and optional leading arguments. Spread syntax is often clearer than apply when the input is iterable. A bound function used with new still constructs from the original target: the newly created instance becomes this, so the bound thisArg is ignored, while bound leading arguments remain. Binding an arrow cannot change its lexical this. Avoid rebinding on every registration because each bind call creates a distinct callback.

Was this clear?
11 How do currying, partial application, composition, and pipe differ in practical code? Mid occasional reveal ▾ hide ▴

Currying transforms a function of several conceptual arguments into a chain that accepts them in stages, usually one group at a time. Partial application fixes some arguments and returns a function for the rest without requiring that unary shape. Composition connects output to input; compose commonly reads right to left, while pipe reads left to right. A reusable helper must define arity, placeholder, receiver, sync-versus-async, and error behavior. Using Function.length as the whole currying contract is fragile because default and rest parameters do not describe the full semantic input contract.

Was this clear?
12 How do debounce and throttle differ, and what lifecycle controls should production wrappers expose? Mid common reveal ▾ hide ▴

Debounce waits for a quiet interval and collapses a burst, so it suits search input after typing stops. Throttle limits execution to at most a chosen rate, so it suits continuous scroll or pointer updates. Leading and trailing behavior must be explicit because it changes which call supplies arguments and whether a final update runs. A production wrapper should preserve the intended receiver, retain the latest arguments deliberately, and expose cancel; flush can also be useful. On teardown, cancel timers and abort any superseded asynchronous request, because suppressing a callback does not cancel work already started.

read more
Was this clear?
41 What changes when a function declaration is replaced with a const arrow function? Mid occasional reveal ▾ hide ▴

In Node 24, a function declaration is initialized when its scope is instantiated, so an earlier call in that scope can work. A const arrow binding stays in the temporal dead zone until its initializer runs. The arrow also has no own this, arguments, super, or new.target, and it cannot be constructed with new. The forms are interchangeable only when callers depend on none of those capabilities. Before an automated refactor, search early calls, constructor uses, receiver-sensitive calls, and arguments; otherwise a cosmetic rewrite can create startup failures or silently capture an outer value.

Was this clear?
42 How does a class-field arrow differ from a prototype method? Mid common reveal ▾ hide ▴

In Node 24, an ordinary class method is one non-enumerable function on the prototype and receives this from each call. An arrow field is initialized as an own property for every instance and closes over that instance’s this, so passing it as a callback keeps the receiver. That convenience costs one function identity per instance and changes inheritance, spying, and prototype patching: an own field can shadow a prototype override. Prefer a prototype method for shared polymorphic behavior; use an arrow field only when extraction-safe identity is part of the contract, and test cleanup with the same stored callback.

Was this clear?
43 How do strict and non-strict functions treat the thisArg passed to call or apply? Mid common reveal ▾ hide ▴

In Node 24, call() and apply() pass the requested thisArg unchanged to a strict ordinary function. A non-strict ordinary function substitutes the global this value for null or undefined and boxes primitive receivers such as numbers. ES modules and class bodies are strict automatically, but a function’s own strictness governs its receiver normalization. Arrow functions ignore the supplied receiver because they use lexical this. Do not rely on sloppy boxing or global substitution as an API feature; use strict code and validate an explicit receiver, especially when borrowing a method across objects.

Was this clear?
44 When does apply accept arguments that spread syntax rejects, and what limit do both approaches share? Mid common reveal ▾ hide ▴

In Node 24, fn.apply(receiver, args) accepts an array-like object with indexed properties and a length; it need not implement iteration. fn(...args) instead requires an iterable, so a plain {0: value, length: 1} works with apply but not spread. Spread is usually clearer for arrays and other iterables, while apply remains useful at array-like boundaries. Both turn the collection into individual call arguments and therefore face engine argument-count limits. Never spread an unbounded collection into Math.max() or another call; aggregate incrementally or process bounded chunks instead.

Was this clear?
45 How does super.method() choose an implementation while preserving this, and what does detaching the method break? Mid common reveal ▾ hide ▴

In Node 24, super.method() starts property lookup at the parent prototype, but invokes the result with the current this; it does not turn the parent prototype into the receiver. That lets a base implementation operate on derived-instance fields and participate in an override chain. If the derived method itself is detached and called plainly, strict class semantics give it this === undefined before it reaches super, so field access fails. Preserve the property call, wrap it, or bind once. Avoid calling overridable methods from a base constructor, because derived fields are not initialized until super() returns.

Was this clear?
46 Exactly when does a default parameter run, and how should null be handled? Junior common reveal ▾ hide ▴

In Node 24, a default initializer runs at call time only when its argument is omitted or exactly undefined. An explicit null, 0, false, or empty string remains the supplied value. Initializers run left to right for each call, so a later default may reference an earlier parameter, and creating an object there produces a fresh object per applicable call. Decide whether null means absent or invalid at the boundary: normalize with ?? only for the former, otherwise reject it. A destructured parameter also needs an outer default before missing undefined can be safely unpacked.

read more Functions
Was this clear?
47 Why do closures created in a let loop see different values while var closures often do not? Mid common reveal ▾ hide ▴

In Node 24, a for loop with a lexical let declaration creates a new binding for each iteration, so each closure resolves its own iteration’s variable. A var declaration is function-scoped and supplies one shared binding; callbacks that run later normally observe its final value. Closures retain bindings, not frozen value copies, so reassigning any captured outer let can produce the same surprise outside loops. Prefer let for loop indexes, or pass the needed value into a small factory. Also classify captured objects as shared or per iteration; let does not clone an outside mutable object.

read more Closures
Was this clear?
48 How would you prove that a closure is retaining memory unintentionally? Mid occasional reveal ▾ hide ▴

In Node 24, collection depends on reachability, not whether references form a cycle or a local was assigned null. Reproduce the lifecycle repeatedly under stable input, take comparable heap snapshots, and inspect the retaining path from a root to the growing objects. A common path is a long-lived emitter to a registered callback, then through the closure environment to component state. Keep the exact callback identity and remove it during teardown, or use an owned abort signal. Confirm that retained counts plateau afterward; one heap increase may only reflect warm-up, delayed collection, or an intentional cache.

Was this clear?
49 Why is Function.length an unsafe completion rule for a generic curry helper? Mid common reveal ▾ hide ▴

In Node 24, Function.length counts parameters only up to the first parameter with a default, excludes a rest parameter, and counts one destructuring pattern as one parameter. It is descriptive metadata, not the business arity. A curry helper may therefore invoke (base, options = {}, request) after receiving only base, while a rest-only target reports zero. Require an explicit arity for optional or variadic signatures, or replace generic currying with a named configuration factory. Test every supported grouping, extra and empty calls, placeholders if any, and the exact point where the business function runs.

Was this clear?
50 What must an asynchronous pipe define that a synchronous composition helper does not? Senior common reveal ▾ hide ▴

In Node 24, a synchronous pipe passes each return value directly to the next stage; if one stage returns a Promise, the next receives that Promise as an ordinary object. An async pipe should adopt one settlement rule, commonly starting with Promise.resolve(input) and chaining stages so both plain values and Promises are awaited. It must also define rejection propagation, cancellation ownership, and whether stages may run only sequentially. Name stages whose input and output shapes change. A catch-all fallback inside the helper is risky because it can turn a rejected stage into plausible success far from the responsible boundary.

Was this clear?
91 Why is top-level this an unsafe source of application context in Node.js? Mid occasional reveal ▾ hide ▴

In Node 24, top-level this depends on the module format: it is undefined in an ES module, while a CommonJS file runs in a wrapper where top-level this refers to module.exports, not globalThis. An arrow created there captures that environment and cannot be rebound with call, apply, or bind. Moving the file or changing the nearest package type can therefore alter assumptions. Pass dependencies explicitly or create callbacks inside a receiver-bearing method. Do not use top-level this as portable global storage; use an intentional module export or globalThis only when process-wide ownership is truly required.

read more this binding
Was this clear?

Async

8 questions
13 How do tasks and microtasks interact, and how can microtasks starve browser work? Mid common reveal ▾ hide ▴

A task runs JavaScript to completion. At the following microtask checkpoint, the host drains queued Promise reactions, queueMicrotask callbacks, and other microtasks, including new microtasks they enqueue, before moving to another task and normally before rendering. This explains why a resolved Promise callback runs before a zero-delay timer scheduled in the same turn. It also creates a boundary: a self-perpetuating microtask chain can delay timers, input handling, and paint. Break substantial work into bounded chunks and yield through a task-level scheduling mechanism when the browser needs an opportunity to render or handle input.

Was this clear?
14 How do you decide whether asynchronous operations should run sequentially or concurrently? Junior common reveal ▾ hide ▴

Model data and side-effect dependencies first. If operation B needs the result of A, start B after awaiting A. If independent operations may overlap, start their Promises before awaiting the group, commonly with Promise.all. Writing await A(); await B(); serializes them even when no dependency exists, while constructing both Promises first allows overlap. Concurrency is not automatically unbounded parallelism: a large input set may need a worker pool, rate limit, or backpressure. Preserve input identity in results, define the failure policy, and pass cancellation signals so abandoned work can stop cooperatively.

read more
Was this clear?
15 What failure policies do the main Promise combinators express, and what do they not do? Mid common reveal ▾ hide ▴

Promise.all requires every input to fulfill and rejects when one rejects. allSettled waits for every outcome and returns status-tagged records. any fulfills on the first fulfillment and rejects with AggregateError only if all inputs reject. race settles with the first settled input, whether fulfilled or rejected. Returned result order follows input order where a result array exists, not completion order. Crucially, early settlement does not cancel the other operations. Choose from the business success condition, then add AbortSignal or another cooperative cancellation mechanism and await any cleanup the underlying operations require.

read more
Was this clear?
16 Why are async iterators useful for paginated or streaming data, and how should they clean up? Mid occasional reveal ▾ hide ▴

An async iterable exposes Symbol.asyncIterator, and each next call yields a Promise for an iterator result. for await…of requests values one at a time, so a generator can fetch the next page only as consumption advances instead of buffering the whole data set. That creates natural pull-based pacing, although it does not impose a global memory limit by itself. Put owned resource cleanup in finally. When the loop exits early, iterator closing calls return when available, allowing the generator to release a reader, cursor, or connection. Propagate AbortSignal when underlying I/O also needs cancellation.

read more
Was this clear?
17 How does the Streams API represent backpressure, ownership, and cancellation? Senior occasional reveal ▾ hide ▴

A ReadableStream maintains an internal queue and a desired size derived from its queuing strategy. A well-behaved underlying source enqueues only when the consumer has capacity and responds to pull requests, rather than producing without bound. Acquiring a reader locks the stream to that reader; releaseLock gives up the lock but does not cancel the source. cancel signals that the consumer no longer needs data, while pipeTo coordinates reads, writes, backpressure, closure, and error propagation. Always decide who owns cancellation, and avoid tee for large streams unless both branches will consume at compatible rates.

read more
Was this clear?
18 How do switchMap, mergeMap, concatMap, and exhaustMap encode different concurrency policies? Senior rare reveal ▾ hide ▴

switchMap unsubscribes from the previous inner Observable when a new outer value arrives, so it fits replaceable searches. mergeMap keeps multiple inner subscriptions active and may interleave results. concatMap queues outer values and processes inners in order. exhaustMap ignores new outer values while the current inner remains active, which can protect a non-repeatable submission. Unsubscription is the key boundary, but it cancels underlying work only when the Observable teardown actually does so. Choose by ordering, concurrency, and cancellation semantics, then test completion and error behavior rather than selecting an operator by habit.

read more
Was this clear?
37 How do process.nextTick, Promise reactions, and event-loop phases interact in Node.js? Senior occasional reveal ▾ hide ▴

A JavaScript callback runs to completion before either deferred queue is processed. Node then drains its next-tick queue before the Promise microtask queue, and drains newly added entries before advancing through libuv phases such as timers, poll, and check. That priority makes process.nextTick useful for narrow compatibility boundaries but dangerous as a general scheduler: an unbounded chain can starve I/O. Promise reactions and queueMicrotask are more portable, though they can starve task work too. State the execution context because ES module top-level evaluation already occurs within a microtask and can change observed ordering.

Was this clear?
38 Why does marking CPU-heavy JavaScript async not prevent event-loop blocking? Mid common reveal ▾ hide ▴

async changes how a function reports completion; it does not move the body to another thread. The body still runs synchronously until an await suspends it, and awaiting an already completed calculation cannot recover time during which the event-loop thread was occupied. For moderately sized work, process measured chunks and yield through a task-level primitive so timers and I/O get turns. For sustained computation, use worker threads and include message-transfer cost in the design. Measure event-loop delay and tail latency under representative load, because arbitrary chunk sizes can either add overhead or still block too long.

Was this clear?

Browser

6 questions
19 How do you implement event delegation without acting on the wrong element? Mid common reveal ▾ hide ▴

Register one listener on a stable ancestor and use event.target to locate the originating node, while event.currentTarget remains the ancestor that owns the listener. Because the target may be a nested icon or text-bearing element, use closest with the intended selector, then verify that the match is inside the delegation root before acting. Delegation depends on event propagation; non-bubbling events, stopPropagation, and shadow boundaries may require capture, a different event, or component-level handling. Keep selectors semantic, validate data read from the DOM, and remove the ancestor listener during teardown.

read more
Was this clear?
20 What must a robust fetch wrapper handle beyond awaiting fetch itself? Mid common reveal ▾ hide ▴

fetch normally rejects for network-level failure or abort, not merely because the server returned 404 or 500, so inspect response.ok or an accepted status range. A response body is a stream and is normally consumed once; clone before consumption only when two consumers are genuinely required. Parsing JSON can fail independently of the HTTP status and should retain response context. Pass an AbortSignal for user cancellation, teardown, or deadlines, and distinguish abort from operational failure. Finally, retries need idempotency rules, bounded attempts, backoff, and respect for server guidance; retrying every failed request can duplicate effects.

read more
Was this clear?
21 How can JavaScript accidentally force repeated layout, and what is the narrow fix? Senior common reveal ▾ hide ▴

Style changes can invalidate layout information. If a loop writes a layout-affecting style and then immediately reads geometry such as getBoundingClientRect or offsetHeight, the browser may have to synchronously update style and layout on each iteration so the read is current. That read-write alternation is layout thrashing. Batch geometry reads first, compute changes in memory, then batch writes, often scheduling visual work with requestAnimationFrame. The boundary is measurement: not every DOM access forces layout, and compositor-friendly properties can avoid layout, but layer promotion is not free and should be verified with performance tooling.

read more
Was this clear?
22 What does IntersectionObserver report, and what should it not be used to guarantee? Mid occasional reveal ▾ hide ▴

IntersectionObserver asynchronously reports when an observed target crosses configured intersection thresholds relative to a root, adjusted by rootMargin. An entry provides geometry, a ratio, and an isIntersecting flag for that observation. It avoids continuous manual scroll measurement, but callbacks are not a pixel-perfect record of every movement and may be delivered after the geometry changed again. Use it for lazy loading, coarse visibility state, or sentinel-based pagination. Do not treat it as proof that an ad was continuously visible for a duration; combine entries with time tracking and page-visibility rules, then unobserve targets on cleanup.

read more
Was this clear?
23 Why can a newly installed service worker fail to control an already open page? Senior occasional reveal ▾ hide ▴

Service workers have install, waiting, and activate stages. A successful update commonly waits while the previous worker still controls open clients, so installation alone does not transfer control to the current page. skipWaiting and clients.claim can accelerate takeover, but doing so may pair old page code with new caching logic and must be designed as a coordinated version transition. Use event.waitUntil to extend install or activate work, version caches explicitly, and delete only caches the application owns. Treat cached responses as data with an invalidation policy, not as a permanent offline copy of every request.

read more
Was this clear?
24 How should a Web Component define its public state and event contract across a shadow boundary? Senior rare reveal ▾ hide ▴

Use properties for rich JavaScript values and attributes for serializable declarative configuration, then define reflection deliberately instead of assuming they stay synchronized. observedAttributes and attributeChangedCallback should normalize input without creating a reflection loop. Shadow DOM isolates internal nodes and much styling, but it is not a security boundary. For an event meant to leave the shadow tree, dispatch a CustomEvent with bubbles and composed set appropriately, and keep detail minimal and documented. Lifecycle callbacks can run more than once, so connectedCallback setup should be paired with idempotence or disconnectedCallback cleanup.

read more
Was this clear?

Node

6 questions
25 Why is it unsafe to memorize one universal ordering for Node.js timers, immediates, and microtasks? Senior common reveal ▾ hide ▴

Node runs callbacks in event-loop phases, while Promise reactions and process.nextTick callbacks are drained at specific checkpoints around JavaScript callbacks. process.nextTick has its own high-priority queue and can starve I/O when recursively filled. Relative ordering between setTimeout(…, 0) and setImmediate depends on where they were scheduled and on the surrounding I/O turn, so there is no single context-free answer. Explain the scheduling context, then trace the relevant phase and checkpoints. Use neither API as a correctness lock; express ordering through awaited Promises, queues, or explicit state transitions.

read more
Was this clear?
26 When does Node concurrency still block the event loop, and when do worker threads help? Mid common reveal ▾ hide ▴

Asynchronous I/O lets Node wait without occupying the JavaScript thread, but JavaScript callbacks still run on the event-loop thread. A long calculation, huge parse, or synchronous filesystem call blocks other callbacks regardless of how the surrounding function was declared. libuv uses a thread pool for selected native operations; it does not automatically move arbitrary JavaScript computation there. Use worker threads for substantial CPU-bound JavaScript that can justify message-passing and serialization overhead. First measure event-loop delay, bound input sizes, and prefer streaming or smaller chunks when the real problem is unbounded data handling.

read more
Was this clear?
27 How should an Express middleware chain establish one clear response and error boundary? Mid common reveal ▾ hide ▴

Each middleware should either finish the response or delegate, and control flow should stop after sending. Calling next after a response, or sending again after next middleware runs, creates duplicate-header failures and confusing ownership. Validate input near the route boundary, keep handlers focused, and forward failures to one terminal error middleware whose four-argument signature distinguishes it from normal middleware. Async rejection forwarding depends on the Express version and wrapper style, so make that convention explicit and test it. The final error handler should map known operational errors, hide internal details, and avoid responding again once headers were sent.

Was this clear?
28 How should you choose a NestJS provider scope, and what goes wrong with hidden mutable state? Senior occasional reveal ▾ hide ▴

Use the default singleton scope for stateless services and safely shared resources such as connection pools. Request scope creates an instance per request and propagates through dependent providers, adding allocation and dependency-graph cost, so reserve it for genuinely request-bound state. Transient scope creates an instance per consumer and is useful only when that ownership is intentional. A singleton that stores the current user or request data introduces cross-request races and leaks. Pass request-specific values as method arguments or through an explicit context abstraction, and keep module exports narrow so dependency ownership remains visible.

read more
Was this clear?
29 How does Deno permission control support least privilege, and where is its boundary? Mid occasional reveal ▾ hide ▴

Deno starts without broad file, network, environment, subprocess, or similar access unless permissions are granted. Grant the narrowest resource set, such as specific hosts or directories, rather than using an all-permissions flag. A program may query or request permissions, but deployment policy should decide whether interactive prompting is acceptable. Permissions constrain runtime capabilities; they do not prove imported code is trustworthy, validate application authorization, or protect data once access is granted. Review the dependency graph, pin and verify dependencies according to project policy, separate duties into processes when useful, and test that missing permissions fail safely.

read more
Was this clear?
30 What is a safe IPC boundary between an Electron renderer and the main process? Senior rare reveal ▾ hide ▴

Treat renderer messages as untrusted input, especially when any remote or user-controlled content can render. Keep context isolation enabled, avoid exposing raw ipcRenderer or Node capabilities, and publish a small allowlisted API from the preload script through the context bridge. In the main process, validate channel, sender, argument shape, authorization, and target resource before performing privileged work. Prefer request-response handlers with explicit result and error schemas over a generic execute channel. Navigation, new-window creation, and external URL opening need separate allowlists. IPC isolation reduces capability exposure; it does not replace normal input validation.

read more
Was this clear?

Patterns and tooling

6 questions
31 When does a factory improve JavaScript design, and when is it unnecessary indirection? Mid occasional reveal ▾ hide ▴

A factory helps when creation must validate configuration, choose among implementations, assemble dependencies, or hide construction details behind a stable interface. It gives callers one policy boundary and can make tests inject substitutes without knowing concrete constructors. It is unnecessary when it merely renames new for one simple class and adds no invariant or variation. Return objects with a documented behavioral contract, fail early on unsupported types, and keep lifecycle ownership explicit. If the factory creates sockets, workers, or subscriptions, the returned abstraction should expose close or dispose rather than hiding cleanup.

read more
Was this clear?
32 How do Observer and publish-subscribe differ, and what operational concerns do they share? Senior occasional reveal ▾ hide ▴

In a direct Observer design, a subject knows its observer collection and notifies it. Publish-subscribe places a broker or event channel between publishers and subscribers, reducing direct knowledge but making event contracts and tracing more important. Both need explicit subscription ownership, unsubscribe behavior, duplicate-listener policy, and a rule for errors raised by handlers. Decide whether delivery is synchronous, queued, ordered, or concurrent; those choices affect reentrancy and backpressure. Never let one forgotten subscription keep an entire component graph alive. Return an unsubscribe handle and test teardown as part of the contract.

read more
Was this clear?
33 How do you decide whether state should be local, global, derived, persisted, or treated as server state? Mid common reveal ▾ hide ▴

Start with ownership and authority. Keep state local to the smallest subtree that needs to change it. Derive values that can be computed from existing state instead of storing a second synchronized copy. Promote state only when several distant consumers need coordinated writes. Server state has remote authority, staleness, retries, and cache invalidation, so use a query cache rather than pretending it is ordinary client state. Persistence is another boundary, not a default: version the stored shape, validate on read, handle migration and quota failure, and never place secrets in browser storage merely for convenience.

read more
Was this clear?
34 How do you make a Jest asynchronous test fail reliably for the right reason? Mid common reveal ▾ hide ▴

Return or await the Promise that represents the behavior under test; otherwise the test can finish before the assertion runs. For an expected rejection, await expect(promise).rejects or use try/catch with an assertion count so an unexpected fulfillment cannot pass silently. Fake timers control scheduled time, but Promise microtasks and external I/O may need separate advancement or mocking according to the selected timer mode. Restore timers, spies, and global changes after each test. Prefer testing observable output over call-by-call implementation details, and make each test own its data so order and parallel execution do not affect it.

read more
Was this clear?
35 Why are Playwright locators and web-first assertions more reliable than fixed sleeps? Junior common reveal ▾ hide ▴

A locator resolves against the current page when an action or assertion runs, and Playwright waits for relevant actionability conditions such as visibility, stability, and ability to receive events. Web-first assertions retry until their condition succeeds or the timeout expires. A fixed sleep only guesses when the application will be ready, wasting time on fast runs and still failing on slow ones. Prefer role, label, or test-id locators tied to user-visible contracts, keep browser contexts isolated, and wait for a specific observable state. Auto-waiting cannot repair an ambiguous locator or an application that never exposes readiness.

read more
Was this clear?
36 How do x-show and x-if differ in Alpine.js, and what lifecycle tradeoff follows? Junior occasional reveal ▾ hide ▴

x-show keeps the element in the DOM and toggles its display state, so local DOM state and attached component work remain present while hidden. x-if conditionally creates and removes DOM through a template, so it avoids retaining a large inactive subtree but pays creation and teardown cost and resets element-local state. Choose from lifecycle semantics, not just visibility. Use x-show for frequently toggled lightweight UI and x-if for expensive or semantically absent content. If initial hidden content might flash before Alpine initializes, pair the state with x-cloak and the corresponding CSS rule.

read more
Was this clear?