Right or Wrong?
Prompt
What does log() output in the code below? And how would you fix it so that it logs the correct count?
function createIncrement() {
let count = 0;
function increment() {
count++;
}
let message = `Count is ${count}`;
function log() {
console.log(message);
}
return [increment, log];
}
const [increment, log] = createIncrement();
increment();
increment();
increment();
log(); // What is logged?Think about when the message variable gets its value.
Is it when log() is called, or when createIncrement()
is called?
Template literals like `Count is ${count}` evaluate
immediately when that line runs. They don't create a
"live" connection to the variable. The resulting string is
a snapshot of count at that moment.
Solution
The output is: "Count is 0"
Explanation
This one catches people off guard because it feels like the answer should be "Count is 3". We called increment() three times, count is clearly 3, and log() is supposed to show us the count. So why does it print 0?
The whole thing comes down to when the message variable gets its value.
Look at this line:
let message = `Count is ${count}`;This line runs once, at the moment createIncrement() is called. At that point, count is 0. The template literal evaluates immediately and produces the string "Count is 0". That string gets stored in message. And that's it. The template literal has done its job. It doesn't maintain any connection to count. It's just a plain string now.
Later, when we call increment() three times, count goes from 0 to 3. But message is still sitting there holding "Count is 0" because nobody reassigned it. Strings don't update themselves. message was set once and never touched again.
When log() finally runs, it reads message through the closure and logs whatever is in it: "Count is 0". The closure gives log() access to message, but message itself is stale.
The fix
Move the template literal inside the log() function so it evaluates fresh every time log() is called:
function createIncrement() {
let count = 0;
function increment() {
count++;
}
function log() {
const message = `Count is ${count}`;
console.log(message);
}
return [increment, log];
}Now message is created inside log(), so it reads the current value of count each time. The closure still has access to count (closures capture variables by reference, not by value), so after three increments it sees 3.
Why this question matters
This is testing the difference between capturing a variable and capturing a value. Closures capture variables. They hold a reference to the variable itself, not a frozen copy. But template literals produce values. When you write `Count is ${count}`, the ${count} part is evaluated right there, producing a concrete string.
The bug happens because message captures a value (the evaluated string) instead of staying connected to the variable (count). If you need a value that stays current, you have to compute it at the point where you need it, not earlier.
This same pattern shows up in real code more often than you'd think. Logging functions that capture formatted messages at creation time instead of at log time, event handlers that close over a stale variable, and React components that reference a value from a previous render are all variations of this exact bug.