Last updated: June 26, 2026
50 of 50 questions
var is function-scoped and hoisted; let and const are block-scoped with a temporal dead zone. const cannot be reassigned.
== compares after type coercion; === (strict equality) compares value and type with no coercion. Prefer === to avoid surprises.
string, number, bigint, boolean, undefined, null, symbol — everything else (objects, arrays, functions) is a reference type.
undefined means a variable was declared but not assigned; null is an explicit "no value" you assign intentionally.
Hoisting moves declarations to the top of their scope at compile time. var and function declarations are usable before their line; let/const are not.
false, 0, -0, 0n, "", null, undefined, and NaN are falsy. Everything else — including [] and {} — is truthy.
A declaration is hoisted and callable before its line; an expression assigns a function to a variable and is only available after evaluation.
Arrow functions have no own this, arguments, or prototype; this is lexically inherited from the enclosing scope, and they can’t be constructors.
Both use ..., but spread expands an iterable into elements, while rest collects multiple elements into a single array or object.
Destructuring unpacks values from arrays or properties from objects into distinct variables, with support for defaults, renaming, and nesting.
Template literals use backticks to embed expressions with ${} and write multi-line strings without concatenation or escape characters.
map transforms each element into a new array; filter keeps elements passing a test; reduce folds the array into a single accumulated value.
this depends on how a function is called: the object before the dot for methods, the global/undefined for plain calls, or what bind/call/apply sets.
stringify serialises a value to a JSON string; parse turns a JSON string back into a value. They drop functions, undefined, and choke on cycles.
Use an array for ordered collections you iterate; use an object (or Map) for keyed lookups by a unique identifier.
Strict mode opts into a restricted variant of JavaScript that turns silent errors into thrown errors and disables unsafe features.
Primitive values can’t be changed in place — operations create new values — while object contents can be modified through any reference to them.
Optional chaining short-circuits property access on null/undefined returning undefined; ?? supplies a default only when the left side is null or undefined.
A closure is a function bundled with references to its surrounding scope, letting it access those variables even after the outer function returns.
The single-threaded engine runs the call stack, then drains all microtasks (promises), then one macrotask (timers, I/O), repeating each tick.
A Promise represents a future value with three states — pending, fulfilled, or rejected — and once settled it never changes again.
async functions always return a Promise; await pauses execution until a Promise settles, letting you write asynchronous code in a synchronous style.
all rejects on first failure; allSettled waits for every result; race settles with the first to settle; any resolves with the first fulfilled.
Objects link to a prototype object; property lookups walk the prototype chain until found or it reaches null, enabling shared behaviour.
call and apply invoke a function immediately with a chosen this (call takes args list, apply an array); bind returns a new function with this fixed.
Debounce delays execution until activity stops; throttle runs at most once per interval during continuous activity.
A shallow copy duplicates top-level properties but shares nested references; a deep copy recursively clones everything so nothing is shared.
An Immediately Invoked Function Expression runs as soon as it’s defined, historically used to create private scope before block scoping and modules existed.
ESM uses static import/export resolved at parse time and supports tree-shaking; CommonJS uses dynamic require/module.exports resolved at runtime.
Event delegation attaches one listener to a parent and uses event bubbling to handle events from many child elements, including dynamically added ones.
Currying transforms a function of multiple arguments into a sequence of functions each taking one argument, enabling partial application.
Use Map for keyed collections with any key type and reliable iteration order; use Set for collections of unique values with O(1) membership tests.
Use try/catch around await, .catch on promise chains, and handle unhandledrejection globally; errors in async callbacks won’t be caught by outer try/catch.
Generators are functions that can pause and resume with yield, producing a sequence of values lazily via an iterator.
push, pop, splice, sort, and reverse mutate in place; map, filter, slice, concat, and the new toSorted/toReversed return new arrays.
Symbols are unique, immutable primitives often used as non-colliding object keys and to implement well-known protocols like iteration.
The + operator favours string concatenation if either operand is a string; other operators and comparisons convert operands toward numbers.
var is function-scoped, so all callbacks share one binding holding the final value; using let creates a fresh block-scoped binding per iteration.
Leaks come from lingering references: forgotten timers, unremoved listeners, growing caches, and closures holding large objects past their usefulness.
They hold weak references to object keys/values, so entries are garbage-collected when no other reference exists — ideal for metadata without leaks.
Microtasks (promise callbacks, queueMicrotask) run after each task and fully drain before the next macrotask (timers, I/O, UI events).
bind is permanent and ignores later rebinding; arrows ignore call-site this entirely; class field arrows auto-bind per instance at construction.
Immutability enables cheap change detection by reference and predictable state, implemented via copy-on-write spreads or structural sharing libraries like Immer.
Deep recursion overflows the call stack since tail-call optimisation is largely unimplemented; convert to iteration, trampolines, or chunked async work.
A Proxy intercepts fundamental object operations via traps; Reflect provides the matching default behaviours, enabling reactive state, validation, and instrumentation.
Engines like V8 interpret then JIT-compile hot code using hidden classes and inline caches; keeping object shapes and types stable keeps it fast.
Numbers use IEEE-754 double-precision binary floats, which can’t represent decimals like 0.1 exactly, so arithmetic accumulates tiny rounding errors.
NaN ("Not a Number") results from invalid math; it is the only value not equal to itself, so test with Number.isNaN, not ===.
freeze makes an object fully immutable (no add, remove, or change); seal allows modifying existing properties but blocks adding or removing them.
Extend Error to create typed errors with extra context, enabling precise catch handling via instanceof and clearer logging than generic errors.
Upload your resume and get an instant ATS score with keyword gaps — free, no sign-up.
Advanced JavaScript Interview Questions
10 questions
React Interview Questions
50 questions
Node.js Interview Questions