Follow AiTechWorlds on LinkedIn for professional AI content!Follow Now →

How to Pass a JavaScript Interview at Google, Meta, or Amazon

How to pass a JavaScript interview at top tech companies: closures, event loop, promises, DOM questions, system design, and real interview questions answered.

A
AiTechWorlds Team
May 27, 2026 7 min read
📱

Get more content like this on Telegram!

Daily AI tips, notes & resources — free

Join Free →

How to Pass a JavaScript Interview at Google, Meta, or Amazon

The JavaScript interview that changed my career wasn't at a top tech company — it was at a mid-sized company where the interviewer asked me to explain closures without looking it up.

I fumbled. I knew how to use closures. I wrote them every day. But I couldn't explain why they worked or what was happening under the hood.

That failure sent me on a three-month deep dive into how JavaScript actually works. The knowledge I gained didn't just help me pass interviews — it made me a meaningfully better developer.

This guide covers the JavaScript concepts that top-tier companies actually test, with real examples and the kind of explanations that satisfy interviewers.


The Core Concepts You Will Be Tested On

1. Closures

Every intermediate JavaScript interview asks about closures.

What they are:

function makeCounter(initial = 0) {
  let count = initial;  // This variable is "closed over"
  
  return {
    increment: () => ++count,
    decrement: () => --count,
    value: () => count,
    reset: () => { count = initial; },
  };
}

const counter = makeCounter(10);
counter.increment();  // 11
counter.increment();  // 12
counter.value();      // 12
counter.reset();
counter.value();      // 10

count is a private variable accessible only through the returned functions. This is the module pattern — the basis for encapsulation in JavaScript.

Common interview question: Explain why this prints [3, 3, 3] instead of [0, 1, 2]:

const funcs = [];
for (var i = 0; i < 3; i++) {
  funcs.push(function() { return i; });
}
funcs.forEach(f => console.log(f()));  // 3, 3, 3

Because var has function scope (not block scope), there's only one i, and by the time the functions run, i is 3. Fix it with let (which creates a new binding per iteration) or an IIFE:

// Fix 1: use let
for (let i = 0; i < 3; i++) {
  funcs.push(() => i);
}

// Fix 2: IIFE to capture current value
for (var i = 0; i < 3; i++) {
  funcs.push((function(j) { return () => j; })(i));
}

2. The Event Loop

The question: What is the output of this code?

console.log('1');

setTimeout(() => console.log('2'), 0);

Promise.resolve().then(() => console.log('3'));

console.log('4');

Answer: 1, 4, 3, 2

Why? The event loop order:

  1. Synchronous code runs first: 1, 4
  2. Microtask queue is drained: Promise .then callback → 3
  3. Task queue: setTimeout callback → 2

Promise callbacks are microtasks and always run before setTimeout callbacks, even at 0ms delay.

More complex example:

async function foo() {
  console.log('A');
  await Promise.resolve();
  console.log('B');
}

console.log('start');
foo();
console.log('end');

// Output: start, A, end, B

foo() starts, logs A, hits await, and suspends — yielding back to the call stack. end logs. Then the microtask (the resumed async function) logs B.

3. this Binding

The four rules:

// 1. Default binding: standalone function call
function show() { console.log(this); }
show();  // window (strict mode: undefined)

// 2. Implicit binding: method call
const obj = {
  name: 'Alice',
  greet() { console.log(this.name); }
};
obj.greet();  // 'Alice' — this is obj

// 3. Explicit binding: call, apply, bind
function greet(greeting) { console.log(`${greeting}, ${this.name}`); }
greet.call({ name: 'Bob' }, 'Hello');   // 'Hello, Bob'
greet.apply({ name: 'Carol' }, ['Hi']); // 'Hi, Carol'
const boundGreet = greet.bind({ name: 'Dave' });
boundGreet('Hey');  // 'Hey, Dave'

// 4. new binding: constructor
function Person(name) { this.name = name; }
const alice = new Person('Alice');
alice.name;  // 'Alice'

Arrow functions don't have their own this — they inherit from the enclosing scope:

const timer = {
  count: 0,
  start() {
    setInterval(() => {
      this.count++;  // Arrow function: this is the timer object
      console.log(this.count);
    }, 1000);
  }
};

4. Prototype and Inheritance

function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  return `${this.name} makes a noise.`;
};

function Dog(name) {
  Animal.call(this, name);  // Call parent constructor
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.bark = function() {
  return `${this.name} barks.`;
};

const dog = new Dog('Rex');
dog.speak();  // 'Rex makes a noise.'
dog.bark();   // 'Rex barks.'

Modern equivalent with classes:

class Animal {
  constructor(name) { this.name = name; }
  speak() { return `${this.name} makes a noise.`; }
}

class Dog extends Animal {
  bark() { return `${this.name} barks.`; }
}

Common Utility Implementation Questions

Companies often ask you to implement common utilities from scratch:

Debounce

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

// Usage: search input that waits for user to stop typing
const search = debounce((query) => fetchResults(query), 300);
input.addEventListener('input', (e) => search(e.target.value));

Throttle

function throttle(fn, limit) {
  let lastCall = 0;
  return function(...args) {
    const now = Date.now();
    if (now - lastCall >= limit) {
      lastCall = now;
      return fn.apply(this, args);
    }
  };
}

// Usage: scroll handler that runs at most once per 100ms
window.addEventListener('scroll', throttle(handleScroll, 100));

Deep Clone

function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') return obj;
  if (Array.isArray(obj)) return obj.map(deepClone);
  
  return Object.fromEntries(
    Object.entries(obj).map(([key, value]) => [key, deepClone(value)])
  );
}

Promise.all Implementation

function myPromiseAll(promises) {
  return new Promise((resolve, reject) => {
    const results = [];
    let completed = 0;
    
    if (promises.length === 0) return resolve([]);
    
    promises.forEach((promise, index) => {
      Promise.resolve(promise)
        .then(value => {
          results[index] = value;
          if (++completed === promises.length) resolve(results);
        })
        .catch(reject);
    });
  });
}

React-Specific Interview Questions

For frontend roles, expect React questions:

What is the virtual DOM? React maintains a virtual representation of the DOM in memory. When state changes, React re-renders the virtual DOM, diffs it against the previous version (reconciliation), and applies only the minimum necessary changes to the real DOM.

Why shouldn't you use array indexes as keys? Keys help React identify which items changed. Using indexes means React may incorrectly reuse DOM elements when items are added/removed/reordered, causing visual bugs and incorrect state.

What is the rules of hooks? (1) Only call hooks at the top level — not inside conditions, loops, or nested functions. (2) Only call hooks from React function components or custom hooks. This ensures hooks are called in the same order every render, which React relies on for correct state tracking.


Interview Preparation Checklist

  • Closures, scope chain, IIFE
  • Event loop, microtasks vs macrotasks
  • this binding rules (4 types + arrow functions)
  • Prototypal inheritance
  • Implement debounce, throttle, deep clone
  • Promises: chains, Promise.all, Promise.race, error handling
  • ES6+: destructuring, spread, modules, classes, optional chaining
  • React: virtual DOM, reconciliation, hooks rules, useEffect dependencies
  • 20–30 LeetCode problems in JavaScript (arrays, strings, trees)

For strengthening the JavaScript fundamentals tested in interviews, our modern JavaScript 2025 guide covers ES6+ in depth. For async/await mastery, our JavaScript async/await guide goes deep on Promises. And for the React-specific knowledge that frontend interviews test, our React hooks tutorial covers every hook thoroughly.


Frequently Asked Questions

What JavaScript topics do FAANG companies ask?

Closures, event loop, async/await, prototypes, this binding, DOM, and front-end system design. Algorithm problems use JavaScript as the implementation language.

How do I prepare for a JavaScript interview?

Master fundamentals, implement utilities (debounce, throttle, deep clone), do 20–30 LeetCode problems, and practice explaining your thinking aloud.

What is a closure?

A function that retains access to variables from its outer scope after that scope has finished executing. Basis for the module pattern and private state in JavaScript.

What is the event loop?

JavaScript's concurrency model: single-threaded execution, call stack, microtask queue (Promises), task queue (setTimeout). After each task, all microtasks run before the next task.

Share this article:

Frequently Asked Questions

Google, Meta, and Amazon JavaScript interviews typically cover: closures and scope, the event loop and async JavaScript, prototypes and inheritance, this binding rules, common array/object methods, DOM manipulation, design patterns (module, observer, factory), and front-end system design. Algorithm and data structure questions use JavaScript as the implementation language.
A

AiTechWorlds Team

✓ Verified Writer

The AiTechWorlds team is passionate about AI, technology, and education. We create high-quality, research-backed content to help you learn, grow, and succeed in the modern digital world.

Related Articles

10K+ Members Growing Daily

Get Free AI Notes Daily

Join AiTechWorlds on Telegram and get daily AI tips, prompt engineering templates, coding resources, and exclusive content — 100% free!

📚 Free Study Notes🤖 AI Tips Daily⚡ Prompt Templates💻 Coding Resources
Join Free Channel

No spam. Leave anytime.

!