McTaba Labs logo
By Bonaventure Ogeto|

JavaScript Interview Questions You Will Actually Get Asked

JavaScript interviews for junior roles test your understanding of closures, the event loop, promises vs callbacks, and how this behaves. The questions below are the ones that actually appear in interviews, not a dump of 100 trivia items. Each answer includes runnable code.

Closures and scope

Q: What is a closure?

A closure is a function that remembers the variables from the scope where it was created, even after that scope has finished executing.

function makeCounter() {
  let count = 0;
  return function () {
    count++;
    return count;
  };
}

const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

The inner function "closes over" the count variable. Each call to makeCounter() creates a new, independent counter.

Q: What is the output of this code?

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Output: 3, 3, 3 (not 0, 1, 2)

Because var is function-scoped, all three callbacks share the same i, which is 3 by the time the timeouts fire. Fix it with let (block-scoped) instead of var.

The event loop and asynchronous code

Q: What is the event loop?

JavaScript runs on a single thread. The event loop is the mechanism that handles asynchronous operations. When you call setTimeout or fetch, the operation is handed off to the browser or Node.js runtime. When the operation completes, its callback is placed in a queue. The event loop picks callbacks from the queue and runs them on the main thread when the call stack is empty.

Q: What is the output of this code?

console.log("1");
setTimeout(() => console.log("2"), 0);
Promise.resolve().then(() => console.log("3"));
console.log("4");

// Output: 1, 4, 3, 2

Synchronous code runs first (1, 4). Microtasks (promises) run before macrotasks (setTimeout), so 3 prints before 2, even though both have a delay of 0.

Promises and async/await

Q: What is a Promise?

A Promise represents a value that may not be available yet. It is in one of three states: pending, fulfilled, or rejected.

function fetchUser(id: number): Promise<string> {
  return new Promise((resolve, reject) => {
    if (id > 0) {
      resolve(`User ${id}`);
    } else {
      reject(new Error("Invalid ID"));
    }
  });
}

// Using .then/.catch
fetchUser(1)
  .then((user) => console.log(user))
  .catch((err) => console.error(err));

// Using async/await
async function main() {
  try {
    const user = await fetchUser(1);
    console.log(user);
  } catch (err) {
    console.error(err);
  }
}
main();

Q: When would you use Promise.all vs Promise.allSettled?

Promise.all rejects as soon as any promise rejects. Use it when all results are required. Promise.allSettled waits for all promises to complete regardless of success or failure. Use it when you want partial results.

The this keyword

Q: How does this work in JavaScript?

this depends on how a function is called, not where it is defined:

  • In a regular function call, this is the global object (or undefined in strict mode)
  • In a method call (obj.method()), this is the object
  • In an arrow function, this is inherited from the enclosing scope
  • With bind, call, or apply, you set this explicitly
const user = {
  name: "Wanjiku",
  greet() {
    console.log(`Hi, I am ${this.name}`);
  },
  greetLater() {
    // Arrow function inherits this from greetLater
    setTimeout(() => console.log(`Hi, I am ${this.name}`), 100);
  },
};

user.greet();      // Hi, I am Wanjiku
user.greetLater(); // Hi, I am Wanjiku

const greet = user.greet;
greet();           // Hi, I am undefined (this is global)

Practical coding questions

Q: Remove duplicates from an array.

const removeDuplicates = (arr: any[]) => [...new Set(arr)];
console.log(removeDuplicates([1, 2, 2, 3, 3, 3])); // [1, 2, 3]

Q: Debounce a function.

function debounce(fn: Function, delay: number) {
  let timer: ReturnType<typeof setTimeout>;
  return function (...args: any[]) {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };
}

const handleSearch = debounce((query: string) => {
  console.log("Searching:", query);
}, 300);

Q: Deep clone an object without using JSON.parse/stringify.

function deepClone<T>(obj: T): T {
  if (obj === null || typeof obj !== "object") return obj;
  if (Array.isArray(obj)) return obj.map(deepClone) as T;
  const clone = {} as T;
  for (const key in obj) {
    if (Object.hasOwn(obj, key)) {
      (clone as any)[key] = deepClone((obj as any)[key]);
    }
  }
  return clone;
}

Frequently Asked Questions

Should I learn TypeScript before a JavaScript interview?
If the job uses TypeScript, yes. If the posting says JavaScript, focus on core JS. Understanding types helps even in JS-only interviews because you can articulate your reasoning more clearly.
How important are algorithmic questions in JS interviews?
At junior level, most companies focus on language fundamentals and practical coding (build a component, fetch data, handle events). Algorithm-heavy interviews are more common at large companies. Know basic array and string manipulation.
Do interviewers expect ES6+ syntax?
Yes. Arrow functions, destructuring, spread/rest, template literals, let/const, and async/await are standard. Using var or callback pyramids signals that your knowledge is outdated.

Ready to build real-world apps?

Join the McTaba Labs full-stack marathon. Ship 8 production apps with M-Pesa, USSD, and WhatsApp integrations, and get career support until placement.

See Programs