# JavaScript Interview Questions (2026) with Answers

> 30 JavaScript interview questions from junior to senior, each with what a strong answer shows. Practise, then prove the skill with evidence.

Source: https://getlemma.io/skills/javascript/interview-questions

JavaScript interviews test whether you can explain how the language really behaves: coercion, scope, this, the event loop and async error handling. Questions below are grouped by level: junior, mid and senior. Each shows what a strong answer covers and the trap weak answers fall into, with short code where it helps.

[How Lemma tests JavaScript](https://getlemma.io/skills/javascript)

## Junior JavaScript interview questions

1.  ### 1.What types does JavaScript have, and what are the surprises with typeof?

    What a strong answer shows

    There are seven primitive types (string, number, bigint, boolean, undefined, symbol, null) plus objects, which include arrays and functions. typeof null returns "object" for historical reasons, and typeof on a function returns "function". A strong answer checks arrays with Array.isArray and null with === null, rather than trusting typeof.

2.  ### 2.What is the difference between == and ===, and what does each of these lines return?

    ```
    "1" + 2;           // "12": + with a string concatenates
    "3" - 1;           // 2: - converts both sides to numbers
    0 == "";           // true
    null == 0;         // false
    null == undefined; // true
    NaN === NaN;       // false: use Number.isNaN or Object.is
    ```

    What a strong answer shows

    \=== compares without converting types, while == applies coercion rules that are hard to predict. A strong answer explains why + concatenates when either side is a string but - always converts to numbers. It uses === by default, with x == null as the one common deliberate exception, matching null and undefined.

3.  ### 3.What are the differences between var, let and const?

    What a strong answer shows

    var is function-scoped and can be redeclared; let and const are block-scoped and cannot be redeclared in the same scope. const prevents reassigning the binding, not changing the object it points to. A strong answer defaults to const, uses let when a value must change, and avoids var in new code.

4.  ### 4.What is hoisting, and what is the temporal dead zone?

    ```
    sayHi();         // works: the declaration is hoisted with its body
    function sayHi() { console.log("hi"); }

    console.log(a);  // undefined: var is hoisted and set to undefined
    var a = 1;

    console.log(b);  // ReferenceError: b is in the temporal dead zone
    let b = 2;
    ```

    What a strong answer shows

    Declarations are registered before code runs: function declarations with their body, var initialised to undefined. let, const and class are hoisted too but stay uninitialised until their line runs, and touching them earlier throws. The weak answer says let and const "are not hoisted", which cannot explain why they shadow outer variables from the block's start.

5.  ### 5.What is a closure? Give a practical use.

    What a strong answer shows

    A closure is a function together with the variables from the scope where it was created, which it can still read and change later. Practical uses include private state, factory functions, callbacks and memoisation. A strong answer explains that closures capture variables, not copies of values, which is the root of many stale-value bugs.

6.  ### 6.What does each loop log, and why?

    ```
    for (var i = 0; i < 3; i++) {
      setTimeout(() => console.log(i), 0);
    }
    // 3, 3, 3: one shared i

    for (let j = 0; j < 3; j++) {
      setTimeout(() => console.log(j), 0);
    }
    // 0, 1, 2: a fresh j for each iteration
    ```

    What a strong answer shows

    With var there is one i shared by all callbacks, and it is 3 by the time they run. With let the loop creates a fresh binding for each iteration, so each callback sees its own value. A strong answer ties this to closures and block scope rather than to setTimeout itself.

7.  ### 7.Which values are falsy, and when do you use ?? instead of ||?

    What a strong answer shows

    The falsy values are false, 0, -0, 0n, "", null, undefined and NaN; everything else, including empty arrays and objects, is truthy. || falls back on any falsy value, while ?? falls back only on null or undefined. A strong answer uses ?? for defaults where 0 or an empty string are valid, such as a quantity or a label.

8.  ### 8.When do you use map, filter, reduce and forEach, and which array methods mutate?

    What a strong answer shows

    map transforms each item, filter keeps some, reduce folds them into one value, and forEach is for side effects and returns nothing. sort, reverse, splice, push and pop change the original array. A strong answer knows the newer copying versions, toSorted, toReversed, toSpliced and with, and prefers a clear loop to a clever reduce.

9.  ### 9.How do you copy an object, and what is the difference between a shallow and a deep copy?

    ```
    const original = { user: { name: "Ada" }, tags: ["a"] };

    const shallow = { ...original };
    shallow.user.name = "Grace"; // original.user.name is now "Grace" too

    const deep = structuredClone(original);
    deep.user.name = "Linus";    // original is untouched
    ```

    What a strong answer shows

    Spread and Object.assign copy only the top level, so nested objects are still shared with the original. structuredClone makes a deep copy of plain data, but it cannot clone functions or DOM nodes and drops class prototypes. The weak answer reaches for JSON.parse(JSON.stringify(x)), which drops undefined, turns dates into strings and empties Maps and Sets.

10.  ### 10.Explain event bubbling and how event delegation works.

    What a strong answer shows

    Most events travel from the target up through its ancestors, so a parent's listener sees clicks on its children. Delegation puts one listener on a container and uses event.target.closest() to find the item clicked. A strong answer names the benefits, fewer listeners and support for items added later, and knows stopPropagation can break delegated handlers elsewhere.

## Mid-level JavaScript interview questions

1.  ### 11.How is the value of this determined?

    ```
    const user = {
      name: "Ada",
      greet() { return "Hi " + this.name; },
    };

    const greet = user.greet;
    greet();                         // TypeError in strict mode: this is undefined
    greet.call(user);                // "Hi Ada"
    setTimeout(() => user.greet());  // works: still called as a method
    ```

    What a strong answer shows

    For regular functions, this depends on how the function is called: as a method, with new, with call, apply or bind, or plain. Arrow functions have no this of their own and use the one from the surrounding scope. A strong answer shows the classic bug of passing a method as a callback and fixes it with an arrow or bind.

2.  ### 12.How does prototypal inheritance work, and what does the class syntax change?

    What a strong answer shows

    Each object has a link to a prototype, and property lookups walk that chain until they find the key or reach null. class is mostly clearer syntax over the same mechanism: methods live on the prototype. A strong answer adds what is genuinely new, such as private # fields, static blocks and the rule that classes must be called with new.

3.  ### 13.Explain the event loop.

    What a strong answer shows

    JavaScript runs one task at a time on a call stack. When the stack empties, the runtime drains the whole microtask queue, then the browser may render, then the next task runs. A strong answer explains why a long synchronous loop freezes the page and why endless microtasks can starve rendering.

4.  ### 14.In what order does this code log, and why?

    ```
    console.log("1");
    setTimeout(() => console.log("2"), 0);
    Promise.resolve().then(() => console.log("3"));
    queueMicrotask(() => console.log("4"));
    (async () => {
      console.log("5");
      await null;
      console.log("6");
    })();
    console.log("7");
    // 1, 5, 7, 3, 4, 6, 2
    ```

    What a strong answer shows

    Synchronous code runs first, so 1, 5 and 7 print before anything queued. Promise callbacks, queueMicrotask and the code after an await are microtasks, so 3, 4 and 6 come next in the order they were queued. setTimeout schedules a task, so 2 prints last even with a 0 ms delay.

5.  ### 15.How do you handle errors with promises and async/await, and what are the common mistakes?

    What a strong answer shows

    With await, wrap the call in try/catch; with promise chains, end in .catch or the rejection goes unhandled. Common mistakes are a missing await, so the error escapes the try block, and catching errors only to log and swallow them. A strong answer knows return await inside try lets the catch see the rejection, and adds an unhandledrejection handler as a safety net.

6.  ### 16.When would you use Promise.all, allSettled, race and any?

    What a strong answer shows

    all waits for every promise and rejects on the first failure; allSettled waits for all and reports each result. race settles with whichever promise settles first, which suits timeouts; any resolves with the first success. A strong answer adds that all does not cancel the remaining work when one fails, so that needs an AbortController.

7.  ### 17.What is wrong with each of these ways of loading a list of users?

    ```
    // Sequential: each request waits for the previous one
    for (const id of ids) users.push(await fetchUser(id));

    // Parallel: all start at once, rejects on the first failure
    const all = await Promise.all(ids.map((id) => fetchUser(id)));

    // Broken: forEach does not wait for async callbacks
    ids.forEach(async (id) => users.push(await fetchUser(id)));
    ```

    What a strong answer shows

    Awaiting inside a for loop runs the requests one after another, which is slow when they do not depend on each other. forEach ignores the promises its callback returns, so nothing waits and errors go unhandled. A strong answer uses Promise.all for independent work and limits concurrency when the list is large.

8.  ### 18.What is the difference between ES modules and CommonJS?

    What a strong answer shows

    ES modules use static import and export, are analysed before running, and support top-level await and tree shaking. CommonJS require is synchronous and runs at call time, returning the module.exports object. A strong answer adds that ESM imports are live, read-only bindings, and that recent Node versions can require() an ES module without top-level await.

9.  ### 19.What is the difference between debouncing and throttling? Write a debounce.

    ```
    function debounce(fn, wait) {
      let timer;
      return function (...args) {
        clearTimeout(timer);
        timer = setTimeout(() => fn.apply(this, args), wait);
      };
    }
    ```

    What a strong answer shows

    Debounce waits until calls stop for a set time, which suits search-as-you-type. Throttle runs at most once per interval, which suits scroll or resize handlers. A strong implementation clears the previous timer on each call and forwards the arguments and this.

10.  ### 20.What does immutability mean in JavaScript, and how do you achieve it?

    What a strong answer shows

    Primitives are immutable, but objects and arrays can be changed through any reference to them. const does not freeze an object, and Object.freeze is shallow. A strong answer creates new objects with spread and non-mutating methods, and explains why: change detection by reference and fewer shared-state bugs.

11.  ### 21.What commonly causes memory leaks in front-end JavaScript?

    What a strong answer shows

    Leaks happen when something still reachable holds on to data that is no longer needed. Typical causes are listeners and timers never removed, detached DOM nodes still referenced, ever-growing caches, and closures holding large objects. A strong answer pairs every subscription with a teardown, for example in a component's cleanup.

12.  ### 22.What is cross-site scripting, and how do you prevent it in JavaScript code?

    What a strong answer shows

    XSS is when untrusted input runs as script in your page, usually through innerHTML, inline handlers or javascript: URLs. Insert text with textContent, sanitise any HTML you must render with a proven library, and validate URLs before using them in links. A strong answer adds a Content Security Policy as a second layer, and knows framework escape hatches such as dangerouslySetInnerHTML bypass escaping.

## Senior JavaScript interview questions

1.  ### 23.Implement Promise.all.

    ```
    function promiseAll(items) {
      const list = Array.from(items);
      const results = new Array(list.length);
      let remaining = list.length;
      return new Promise((resolve, reject) => {
        if (remaining === 0) resolve(results);
        list.forEach((item, i) => Promise.resolve(item).then((value) => {
          results[i] = value;
          if (--remaining === 0) resolve(results);
        }, reject));
      });
    }
    ```

    What a strong answer shows

    Results must keep input order, not completion order, and the promise rejects on the first failure. A strong answer accepts any iterable, wraps plain values with Promise.resolve, and resolves at once for empty input. Forgetting the empty case leaves the promise pending forever.

2.  ### 24.How do you cancel an in-flight request or a long async operation?

    What a strong answer shows

    Create an AbortController, pass its signal to fetch or your own async functions, and call abort() when the result is no longer needed. AbortSignal.timeout gives a deadline, and AbortSignal.any combines a user cancel with a timeout. A strong answer has custom functions check signal.aborted or listen for the abort event, and treats AbortError and TimeoutError as expected outcomes, not failures.

3.  ### 25.A heavy calculation freezes the page. How do you keep the UI responsive?

    What a strong answer shows

    Long tasks block input and rendering because the main thread runs one task at a time. Split the work into chunks that yield with setTimeout or scheduler.yield() where supported, or move it to a Web Worker. A strong answer knows that yielding with a resolved promise does not help, because microtasks run before rendering.

4.  ### 26.When would you use a WeakMap or WeakRef instead of a Map?

    What a strong answer shows

    A WeakMap holds its keys weakly, so attaching data to an object does not keep that object alive. It suits caches or metadata keyed by DOM nodes or other objects you do not own. A strong answer warns that WeakRef and FinalizationRegistry depend on garbage collection timing, which is unpredictable, so program logic must not rely on them.

5.  ### 27.What is prototype pollution, and how do you defend against it?

    ```
    function merge(target, source) {
      for (const key in source) {
        if (typeof source[key] === "object" && source[key] !== null) {
          target[key] ??= {};
          merge(target[key], source[key]);
        } else {
          target[key] = source[key];
        }
      }
    }
    merge({}, JSON.parse('{"__proto__": {"isAdmin": true}}'));
    ({}).isAdmin; // true: every object now inherits isAdmin
    ```

    What a strong answer shows

    A recursive merge or path setter that copies untrusted keys can write through \_\_proto\_\_ to Object.prototype, adding properties to every object. Defences are to skip \_\_proto\_\_, constructor and prototype keys, and to use Object.create(null) or Map for lookups. A strong answer also validates input against a schema before it reaches such code.

6.  ### 28.What are generators and async iterators, and when would you use for await...of?

    ```
    async function* items(url) {
      while (url) {
        const res = await fetch(url);
        const page = await res.json();
        yield* page.items;
        url = page.next;
      }
    }

    for await (const item of items("/api/items")) {
      if (matches(item)) break; // stops before fetching more pages
    }
    ```

    What a strong answer shows

    A generator pauses at each yield and produces values on demand, so it can model lazy or infinite sequences. An async generator does the same with awaited values, which suits paginated APIs and streams. A strong answer notes that breaking out of for await...of calls the generator's return, so no further pages are fetched.

7.  ### 29.How do dynamic import() and code splitting work, and what are the trade-offs?

    What a strong answer shows

    import() loads a module at runtime and returns a promise, and bundlers turn each call into a separate chunk. Splitting by route or by rarely used feature shrinks the first load, but each split adds a request and possible waterfalls. A strong answer preloads chunks the user is likely to need and handles the failure case when a chunk cannot load.

8.  ### 30.How does the Node.js event loop differ from the browser's?

    What a strong answer shows

    Node runs its loop in phases, including timers, poll for I/O and check for setImmediate callbacks. In CommonJS, process.nextTick callbacks run before promise microtasks, and heavy use of either can starve I/O. A strong answer knows setTimeout(fn, 0) versus setImmediate ordering is not guaranteed in the main module, but setImmediate runs first inside an I/O callback.

![Painting of an olive grove in soft sunlight with hills beyond](https://cdn.sanity.io/images/islu4peo/production/613eb3f93566423c9adf45246f2cf1a61437c04c-1680x1120.jpg?w=1080&fm=webp&q=68&fit=max)

## Prove it instead of claiming it.

Answers show you can talk about JavaScript. A dated test result and live sessions on a Skills Passport show you can do it. Lemma is in early access.

## JavaScript interviews: common questions

### Should I learn TypeScript before a JavaScript interview?

Many front-end roles now use TypeScript, so expect to read typed code. The questions themselves usually test runtime behaviour, which types do not change. Learn the runtime first, then the type features you would use every day: unions, generics and narrowing.

### Why do JavaScript interviews ask you to predict console output?

Output puzzles check whether you hold an accurate model of the event loop, coercion and scope. Interviewers care more about the reasoning than the final order. Walk through each queue or binding step aloud instead of guessing.

### Is there a way to test my JavaScript knowledge before interviews?

Answer the questions on this page aloud, then write the code ones from memory and run them. Lemma's adaptive JavaScript test asks 15 to 25 questions that adjust to your answers and records a dated level. Use the gaps it shows to decide what to revise first.

## More interview questions

[Browse the skills directory](https://getlemma.io/skills)

-   [SQL interview questionsJunior to senior, with what a strong answer shows](https://getlemma.io/skills/sql/interview-questions)
-   [Product management interview questionsJunior to senior, with what a strong answer shows](https://getlemma.io/skills/product-management/interview-questions)
-   [Python interview questionsJunior to senior, with what a strong answer shows](https://getlemma.io/skills/python/interview-questions)
-   [React interview questionsJunior to senior, with what a strong answer shows](https://getlemma.io/skills/react/interview-questions)
-   [System design interview questionsJunior to senior, with what a strong answer shows](https://getlemma.io/skills/system-design/interview-questions)
-   [AWS interview questionsJunior to senior, with what a strong answer shows](https://getlemma.io/skills/aws/interview-questions)
-   [Node.js interview questionsJunior to senior, with what a strong answer shows](https://getlemma.io/skills/nodejs/interview-questions)
-   [TypeScript interview questionsJunior to senior, with what a strong answer shows](https://getlemma.io/skills/typescript/interview-questions)
-   [Docker interview questionsJunior to senior, with what a strong answer shows](https://getlemma.io/skills/docker/interview-questions)

Practising answers is half of it; the other half is showing the skill. See [how Lemma tests JavaScript](https://getlemma.io/skills/javascript), how [adaptive skills tests](https://getlemma.io/product/assessments) work, or [how interviewers assess technical skills](https://getlemma.io/blog/assess-technical-skills-in-interview).
