JavaScript Fundamentals Interview Questions
50 questions and answers covering JavaScript Fundamentals, from fundamentals through practical, debugging, and design-level topics.
50 of 50 interview questions
What is the difference between `var`, `let`, and `const`?beginnerFundamentals & Syntax
`var` is function-scoped and hoisted with an initial value of `undefined`; `let` and `const` are block-scoped and hoisted into a 'temporal dead zone' where accessing them before their declaration throws. `const` additionally prevents reassigning the binding (though the value it points to, like an object's properties, can still be mutated).
What is the difference between `==` and `===`?beginnerFundamentals & Syntax
`==` performs type coercion before comparing (so `"5" == 5` is `true`); `===` compares both value and type without coercion (so `"5" === 5` is `false`). Using `===` by default avoids coercion surprises.
console.log("5" == 5); // true console.log("5" === 5); // falseWhat are JavaScript's primitive types?beginnerFundamentals & Syntax
`string`, `number`, `boolean`, `undefined`, `null`, `bigint`, and `symbol`. Everything else (objects, arrays, functions) is a non-primitive `object` type.
What is 'truthy' and 'falsy' in JavaScript?beginnerFundamentals & Syntax
Values that coerce to `false` in a boolean context (`0`, `""`, `null`, `undefined`, `NaN`, `false`) are falsy; everything else, including `"0"` and `[]`, is truthy.
Common mistake: Assuming an empty array `[]` or the string `"0"` is falsy -- both are truthy.
What does 'hoisting' mean in JavaScript?intermediateFundamentals & Syntax
Variable and function declarations are conceptually moved to the top of their scope during compilation. `function` declarations are hoisted with their full body (callable before their line); `var` is hoisted as `undefined`; `let`/`const` are hoisted but unusable until their declaration line (the temporal dead zone).
What is `NaN`, and why does `NaN === NaN` evaluate to `false`?intermediateFundamentals & Syntax
`NaN` ('Not a Number') represents an invalid numeric result. By the IEEE 754 spec it is defined as not equal to itself, so checking for it requires `Number.isNaN(x)` rather than `x === NaN`.
What is the difference between `null` and `undefined`?beginnerFundamentals & Syntax
`undefined` means a variable has been declared but has no assigned value yet; `null` is an explicit assignment meaning 'intentionally no value.'
What is template literal syntax, and what does it offer beyond string concatenation?beginnerFundamentals & Syntax
Backtick-delimited strings (`` `Hello ${name}` ``) that support embedded expression interpolation and multi-line strings without explicit `+` concatenation or `\n` escapes.
const name = "Asha"; console.log(`Hello, ${name}!`);What is destructuring, and why is it useful?intermediateFundamentals & Syntax
A syntax for unpacking values from arrays or properties from objects into distinct variables in one statement, reducing repetitive `obj.prop` access -- e.g. `const { name, age } = user;`.
What is 'strict mode' and what does it change?advancedFundamentals & Syntax
Enabled via `"use strict";`, it disallows several error-prone patterns (like assigning to an undeclared variable) by throwing errors instead of silently failing, and disables some legacy syntax.
What is a closure?intermediateFunctions & Scope
A function that retains access to variables from its enclosing scope even after that outer function has returned. Closures are how JavaScript implements private state and factory functions.
function makeCounter() { let count = 0; return () => ++count; } const counter = makeCounter(); counter(); // 1 counter(); // 2What is the difference between an arrow function and a regular function declaration?intermediateFunctions & Scope
Arrow functions don't have their own `this` (they inherit it from the enclosing scope), can't be used as constructors, and don't have an `arguments` object -- regular functions have all three.
How does `this` behave differently in a regular function versus an arrow function used as an object method?advancedFunctions & Scope
A regular function's `this` is determined by how it's called (the object before the dot); an arrow function has no own `this`, so as an object method it inherits `this` from the surrounding lexical scope, often not the object at all.
Common mistake: Defining an object method as an arrow function and expecting `this` to refer to the object.
What are default parameters, and when are they evaluated?beginnerFunctions & Scope
A way to specify a fallback value for a parameter when the caller omits it or passes `undefined` -- `function greet(name = "friend") {}`. The default expression is evaluated fresh on each call where it's needed, not once at definition time.
What is a higher-order function?intermediateFunctions & Scope
A function that takes another function as an argument, returns a function, or both -- e.g. `Array.prototype.map`, which takes a callback and returns a new transformed array.
What is the difference between function scope and block scope?intermediateFunctions & Scope
A function-scoped variable (`var`) is visible throughout the entire function it's declared in, regardless of nested blocks; a block-scoped variable (`let`/`const`) is only visible within the nearest enclosing `{}` block.
What does the rest parameter syntax (`...args`) do in a function signature?intermediateFunctions & Scope
It collects any remaining arguments passed to the function into a real array, letting you write functions that accept a variable number of arguments -- e.g. `function sum(...nums) { return nums.reduce((a, b) => a + b, 0); }`.
What is an Immediately Invoked Function Expression (IIFE), and why was it historically used?advancedFunctions & Scope
A function defined and called immediately, `(function () { ... })();`, historically used to create a private scope and avoid polluting the global namespace before `let`/`const`/ES modules existed.
What is the difference between a pure function and an impure function?intermediateFunctions & Scope
A pure function always returns the same output for the same input and has no observable side effects (no mutating outside state, no I/O); an impure function can depend on or modify state outside its own scope.
Why does a loop using `var` in a `setTimeout` callback commonly produce a bug that `let` fixes?advancedFunctions & Scope
`var` is function-scoped, so all callbacks share the same single variable, which has finished looping by the time any callback runs. `let` creates a fresh binding per loop iteration, so each callback captures its own value.
for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0); } // logs 3, 3, 3 for (let j = 0; j < 3; j++) { setTimeout(() => console.log(j), 0); } // logs 0, 1, 2Common mistake: Using `var` in a loop that schedules async callbacks, then being surprised every callback sees the final loop value.
What is the difference between `map` and `forEach`?beginnerArrays & Objects
`map` returns a new array built from the callback's return values; `forEach` returns `undefined` and is used purely for side effects, not for building a new array.
Common mistake: Using `forEach` and expecting it to return a transformed array like `map` does.
What does `Array.prototype.reduce` do, and when would you use it over `map`/`filter`?intermediateArrays & Objects
`reduce` folds an array down into a single accumulated value (a number, object, or even a new array) by applying a callback across every element -- use it when the result isn't simply a same-length transformed array or a filtered subset.
const total = [10, 20, 30].reduce((sum, n) => sum + n, 0); // 60What is the spread operator, and how is it used to copy an array or object?intermediateArrays & Objects
`...` expands an iterable's elements (or an object's own enumerable properties) in place -- `const copy = [...original];` or `const copy = { ...original };` create shallow copies without mutating the source.
What is the difference between a shallow copy and a deep copy?advancedArrays & Objects
A shallow copy duplicates the top-level structure but nested objects/arrays still reference the same underlying objects; a deep copy recursively duplicates every nested level so no references are shared with the original.
Common mistake: Using `{ ...obj }` to copy an object with nested objects, then mutating a nested property and being surprised the original changed too.
Why should you avoid mutating an array or object you received as a function parameter?intermediateArrays & Objects
Objects and arrays are passed by reference, so mutating a parameter changes the original value the caller holds too, creating hard-to-trace bugs -- returning a new copy instead keeps the function's effects predictable and local.
What is the difference between `Object.keys`, `Object.values`, and `Object.entries`?intermediateArrays & Objects
`Object.keys` returns an array of the object's own enumerable property names; `Object.values` returns their corresponding values; `Object.entries` returns `[key, value]` pairs, useful for iterating with `for...of` or converting to a `Map`.
What does `Array.prototype.find` return if no element matches, and how does that differ from `filter`?beginnerArrays & Objects
`find` returns `undefined` if nothing matches (or the first matching element otherwise); `filter` always returns an array, which is empty if nothing matches.
How do you check whether a value is an array in JavaScript?intermediateArrays & Objects
`Array.isArray(value)` -- using `typeof value === "object"` is not sufficient since arrays and plain objects both report `typeof "object"`.
What is optional chaining (`?.`) and what problem does it solve?intermediateArrays & Objects
`obj?.prop` accesses a property only if `obj` is not `null`/`undefined`, otherwise short-circuits to `undefined` -- it replaces verbose manual chains of `&&` guards when reading nested, possibly-missing properties.
const city = user?.address?.city; // no error even if address is undefinedWhat is the nullish coalescing operator (`??`) and how does it differ from `||`?advancedArrays & Objects
`a ?? b` returns `b` only if `a` is `null` or `undefined`; `a || b` returns `b` for any falsy `a` (including `0` or `""`), which can incorrectly override intentional falsy values.
Common mistake: Using `count || 10` as a default, which incorrectly falls back to 10 even when `count` is legitimately `0`.
What is the difference between `document.querySelector` and `document.getElementById`?beginnerDOM & Events
`getElementById` only matches by exact `id` and is slightly faster; `querySelector` accepts any CSS selector (class, attribute, descendant combinators) and returns the first match.
What is event bubbling?intermediateDOM & Events
When an event fires on an element, it also propagates upward and fires on that element's ancestors, in order, unless `stopPropagation()` is called.
What is event delegation, and why is it useful?advancedDOM & Events
Attaching a single event listener to a common parent element instead of separate listeners on many children, relying on event bubbling and checking `event.target` -- efficient for large or dynamically-added lists of elements.
What does `event.preventDefault()` do?beginnerDOM & Events
It stops the browser's default action for that event, e.g. preventing a form submission from reloading the page, or preventing a clicked link from navigating.
What is the difference between `textContent` and `innerHTML`?intermediateDOM & Events
`textContent` sets/reads plain text and is always safe from injecting markup; `innerHTML` parses its string as HTML, which can execute injected scripts/markup if the string comes from untrusted user input.
Common mistake: Setting `innerHTML` directly from unsanitized user input, opening an XSS vulnerability.
Why is it generally recommended to place `<script>` tags at the end of `<body>`, or use `defer`?intermediateDOM & Events
The DOM hasn't finished parsing until the whole HTML document loads, so a script running earlier can't reliably find elements defined later in the markup; deferring the script (or placing it at the end) ensures the DOM is ready first.
What is the difference between the `DOMContentLoaded` and `load` events on `window`?advancedDOM & Events
`DOMContentLoaded` fires once the HTML is fully parsed, without waiting for stylesheets/images/subframes; `load` fires only after every resource on the page has finished loading.
How do you read the value a user typed into a form's text input?beginnerDOM & Events
Select the input element and read its `.value` property, typically inside a `change` or `input` event listener, or by reading it at submit time within a `submit` event handler.
What is the difference between the `input` and `change` events on a text field?intermediateDOM & Events
`input` fires on every keystroke/value change immediately; `change` fires only once the field loses focus after its value has changed, making it less noisy for validation that shouldn't run on every keystroke.
Why can directly manipulating the DOM in a tight loop (e.g. appending 1,000 elements one at a time) be slow?advancedDOM & Events
Each DOM mutation can trigger the browser to recalculate layout/style ('reflow'), so many small mutations in a loop can each pay that cost -- batching changes (e.g. building a `DocumentFragment` first, then appending once) avoids repeated reflows.
What is a Promise?beginnerAsync & Promises
An object representing the eventual result (or failure) of an asynchronous operation, with three states: pending, fulfilled, or rejected.
What is the difference between `async`/`await` and raw Promise `.then()` chains?intermediateAsync & Promises
`async`/`await` is syntax that lets asynchronous code read like synchronous code (with `try`/`catch` for errors); under the hood it's built entirely on Promises, so both approaches are interoperable, not competing mechanisms.
How do you handle an error from an `await`ed call?intermediateAsync & Promises
Wrap the `await` in a `try`/`catch` block -- a rejected Promise thrown into `await` behaves like a synchronous `throw`, catchable the same way.
async function loadUser(id) { try { const res = await fetch(`/users/${id}`); return await res.json(); } catch (err) { console.error("Failed to load user", err); throw err; } }What does `Promise.all` do, and how does it handle a single rejected promise among several?advancedAsync & Promises
It takes an array of promises and resolves with an array of all their results once every one has fulfilled -- but if any single promise rejects, `Promise.all` immediately rejects with that error, without waiting for the others.
What is `Promise.allSettled`, and when would you prefer it over `Promise.all`?advancedAsync & Promises
It waits for every promise to settle (fulfill or reject) and returns a result for each, rather than short-circuiting on the first rejection -- useful when you want to run independent requests and see which succeeded even if some failed.
What is the event loop, at a conceptual level?advancedAsync & Promises
JavaScript runs on a single thread; the event loop continuously checks whether the call stack is empty, and if so, pulls the next queued callback (from the microtask queue, then the macrotask/callback queue) to run -- this is how async operations like `fetch` or `setTimeout` don't block the main thread.
Why does a resolved Promise's `.then()` callback run before a `setTimeout(fn, 0)` callback?advancedAsync & Promises
Promise callbacks are 'microtasks,' which the event loop drains completely before moving to the next 'macrotask' (like a `setTimeout` callback), regardless of the requested delay.
console.log("1"); setTimeout(() => console.log("2"), 0); Promise.resolve().then(() => console.log("3")); console.log("4"); // logs: 1, 4, 3, 2What does `fetch()` return, and what's a common mistake when checking whether a request 'succeeded'?advancedAsync & Promises
`fetch()` returns a Promise that resolves once headers arrive -- it does NOT reject for HTTP error statuses like 404 or 500, only for network failures. A common mistake is skipping the `response.ok` check and treating any resolved fetch as success.
Common mistake: Not checking `response.ok` and assuming a resolved `fetch()` call means the server returned a successful status.
What is 'callback hell,' and how do Promises help address it?intermediateAsync & Promises
Deeply nested callbacks (each starting a new async step inside the previous one's callback) that become hard to read and reason about; Promises let those steps be chained flatly with `.then()` (or written sequentially with `async`/`await`) instead of nesting.
What is an ES module, and how does `import`/`export` differ from older script-tag-based code sharing?intermediateAsync & Promises
ES modules let a file explicitly declare what it exports and what it imports from other files, with each module's top-level scope kept private by default -- unlike plain `<script>` tags, which all share one global scope unless manually namespaced.