JavaScript Closures — What Does This Output?
This is a daily Javascript challenge from the CodeShot archive. Practice your knowledge of Iife Module Pattern Private State and improve your technical interview readiness.
const fn = (function() {
let x = 0
return {
increment() { x++ },
getValue() { return x }
}
})()
fn.increment()
fn.increment()
console.log(fn.getValue())
Detailed Explanation
Why This Question Matters
If you've spent any time in a JavaScript interview, you've probably run into a question like this. On the surface, it looks like basic arithmetic. But in reality, it's a test of whether you actually understand closures and the Module Pattern.
Many developers struggle with this because they think about scope as a static thing. They assume that once a function finishes executing, everything inside it vanishes. In JavaScript, that's not how it works. Understanding how functions "remember" their environment is the difference between writing buggy code and writing professional, scalable architecture.
Understanding the Code
Let's look at the snippet:
First, notice the parentheses at the end: })(). This is an IIFE (Immediately Invoked Function Expression). We aren't just defining a function; we are executing it the moment it's created.
Inside this IIFE, we declare let x = 0. Then, we return an object containing two methods: increment and getValue.
Here is the magic: the IIFE finishes executing and "returns" that object to the constant fn. Normally, you'd expect the local variable x to be garbage collected because the function is done. However, because the returned object contains methods that reference x, JavaScript keeps x alive in a "closure."
Essentially, x is now a private variable. It’s trapped in a bubble that only increment() and getValue() can access. You cannot call fn.x from the outside—it would return undefined.
Finding the Correct Answer
Now let's trace the execution:
1. fn.increment() is called. The closure looks at x (which is 0), increments it, and now x is 1.
2. fn.increment() is called again. x becomes 2.
3. console.log(fn.getValue()) is called. It returns the current value of x.
The output is 2. (Option C).
If you thought the answer was 0 or undefined, you likely assumed that x was reset every time a method was called, or that x disappeared after the IIFE ran. Neither is true. The state is preserved across calls because the methods share the same lexical environment.
Common Mistakes Developers Make
The most common trip-up is confusing local scope with closure scope.
Beginners often think that since x is defined inside a function, it's "temporary." They forget that if a nested function (or a method in a returned object) references that variable, the variable persists.
Another mistake is forgetting how the IIFE works. If the code had been:
const fn = function() { ... } (without the trailing ()), then fn would be the function itself, not the object. Calling fn.increment() would throw a TypeError because fn would be a function, and functions don't have an increment method unless you explicitly attach one.
Finally, some people confuse this with this. In this specific snippet, we aren't using this.x; we are using x directly from the outer scope. If the code used this.x, the result would be totally different (and likely NaN since this.x would be undefined).
Real-World Usage
You might be wondering, "Why would I ever write code like this?"
In the modern era of ES Modules, we have export and import to handle privacy. But before that, the Module Pattern was the gold standard for creating private state in JavaScript.
You still see this pattern everywhere in production:
1. State Management: If you're building a small store or a counter utility without a heavy framework, this is how you prevent external code from accidentally messing with your internal state.
2. API Clients: You can create a singleton that holds an auth token privately and only exposes methods to fetch data using that token.
3. Library Design: Many older JS libraries use this to hide "helper" functions from the global window object, preventing naming collisions.
Basically, any time you want to say, "I want this variable to be accessible to these three functions, but absolutely nobody else," you're using a closure.
Key Takeaways
fn share the same closure, they all manipulate the same x.Why this matters
Understanding Iife Module Pattern Private State is crucial for passing technical interviews. In real-world applications, this concept often leads to subtle bugs if not handled correctly. For more details, you can always refer to the official MDN Documentation.