Skip to Content
Course content

229: Common JavaScript Interview Questions on Closures and this

Click on the "Edit" button in the top corner of the screen to edit your slide content.

If you've started interviewing for JS roles, you've probably noticed that interviewers are obsessed with closures and the this keyword. It's almost a rite of passage. They aren't just testing if you know the definitions; they're checking if you actually understand how the JavaScript engine handles memory and execution context.

"I get the definition of a closure, but why would I actually use one in a real project?"

In textbooks, closures are usually explained with a simple counter. In the real world, I use closures primarily for data privacy. Since JavaScript didn't have truly private class fields for a long time, closures were our only way to "hide" variables from the global scope so other parts of the app couldn't accidentally mess with them.

Check this out. Imagine you're building a module to handle an API token. You don't want the token sitting in a global variable where any script can grab it:

function createTokenManager(initialToken) {
  let token = initialToken; // This variable is "private"

  return {
    updateToken: (newToken) => {
      token = newToken;
      console.log("Token updated!");
    },
    getToken: () => {
      return `Bearer ${token}`;
    }
  };
}

const myManager = createTokenManager("abc-123");
console.log(myManager.getToken()); // "Bearer abc-123"
console.log(myManager.token); // undefined - it's hidden!

The inner functions updateToken and getToken form a closure. They "remember" the environment where they were created, giving them exclusive access to that token variable. It's a clean way to encapsulate state.

"Why does this suddenly stop working when I put my method inside a callback?"

This is the single most common point of frustration for developers. The rule of thumb is: this is not determined by where a function is defined, but by how it is called.

I've seen this a hundred times in event listeners or timers. Look at this snippet:

const user = {
  name: "Alex",
  greet: function() {
    console.log(`Hi, I'm ${this.name}`);
  }
};

// This works fine
user.greet(); // "Hi, I'm Alex"

// This fails
setTimeout(user.greet, 1000); // "Hi, I'm undefined" (or an error in strict mode)

Why? Because setTimeout doesn't call user.greet(); it takes the function itself and calls it later in a different context (usually the global window or undefined). The link to the user object is severed. To fix this, you can use .bind() to explicitly lock the context, or wrap it in an arrow function.

"What's the actual difference between an arrow function and a regular function when it comes to this?"

Regular functions create their own this context every time they are called. Arrow functions, however, don't have their own this at all. Instead, they inherit this from the surrounding code (lexical scoping).

This makes arrow functions a godsend for closures. If you're inside a class method and you need to run a forEach or a map, using an arrow function ensures that this still refers to your class instance, not the array being iterated over.

class Timer {
  constructor() {
    this.seconds = 0;
  }

  start() {
    setInterval(() => {
      this.seconds++; // 'this' correctly refers to the Timer instance
      console.log(this.seconds);
    }, 1000);
  }
}

const myTimer = new Timer();
myTimer.start();

If I had used function() { this.seconds++; } inside that setInterval, it would have crashed because this would have pointed to the global Window object, which doesn't have a seconds property. I almost always prefer arrow functions for callbacks for exactly this reason.




📋 Practical Task

Build a Private Score Tracker with Context Binding

Your task is to create a createGame function that manages a player's score using a closure to keep the score private. However, you must also implement a "bonus" system that uses a separate method, requiring you to handle the this context correctly.

  • Create a function createGame that initializes a score variable at 0.
  • Return an object with three methods:
    • addPoint(): Increments the score by 1.
    • getScore(): Returns the current score as a string (e.g., "Current score is 5").
    • applyBonus(multiplier): This method should be a regular function that uses this to reference a bonusValue property on the returned object, then adds that multiplied value to the private score.
  • Initialize a game instance, set a bonusValue property on that instance, and use a setTimeout to call applyBonus after 1 second. Ensure you use .bind() or an arrow function so that this.bonusValue is accessed correctly within the timer.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.