When closures are created inside loops, they capture the variables from the surrounding environment, including the loop's variables. Since closures retain references to these variables by capturing the entire environment, they don't actually store the current value of those variables; instead, they maintain references to the variables themselves. As a result, if the loop continues to execute and update its variables, the closures created inside the loop will use the updated values, which might not be the expected behaviour.
Explanation: When the loop runs, the setTimeout callbacks are scheduled, and the closures inside them capture the reference to the variable i. The closures don't have their own copy of i; they share a reference to the same i variable. As the loop iterates, the value of i changes until it reaches 3. Since the closures capture the reference to i, when they finally execute, they use the latest value of i, which is 3.
Solution: To avoid this problem, you can create a new scope inside each iteration of the loop to capture the current value of i. This can be achieved using an Immediately Invoked Function Expression (IIFE) or by using the let keyword, which has block-level scope:
Imagine you're building a simple tab component. You loop through 5 button elements to attach a click handler that alerts the button's index. When you click any button, it always alerts '5'. Why is this happening, and how would you fix it?
We have a loop that's supposed to print numbers 0 through 4 with a one-second delay using setTimeout. Instead, it prints '5' five times. Walk me through why the engine behaves this way and how we can get it to print 0, 1, 2, 3, 4.
We have a React component that renders a list of active file uploads. Inside a loop, we set up a WebSocket listener for each file that references the loop's local state. Users are reporting that progress updates are updating the wrong files or showing stale data. How would you debug this scope issue?
You're writing a Node.js script that processes thousands of database rows in a loop. Inside the loop, you define an inline helper function to format each row before saving. The script is running out of memory on large datasets. Why is defining that function inside the loop problematic for the garbage collector, and how would you refactor it?
We are building a real-time data visualization dashboard that updates 60 times a second. A junior developer wrote a loop that instantiates event handlers inside the render loop, causing massive GC thrashing and frame drops. How do you refactor this to avoid allocation overhead while still maintaining access to the correct contextual data?
You are refactoring a legacy ES5 SDK where block scoping ('let'/'const') isn't fully supported or trusted due to target environments, and we cannot use transpilers. We have complex asynchronous initialization loops that are leaking memory and sharing state. How would you design a clean, memory-efficient pattern using IIFEs or factory functions to isolate scope safely?
In a large-scale micro-frontend architecture, we've noticed memory leaks traced back to dynamically generated event handlers inside loops within legacy shared libraries. How would you address this systematically? What linting rules, architectural boundaries, or custom compiler transforms would you introduce to prevent this across 50+ engineering teams?
We are designing a high-throughput serverless execution environment where cold starts and memory footprints are critical. How does the V8 engine handle closure allocation and context saving inside loops under the hood, and what architectural guidelines would you establish for our team to minimize heap allocation overhead in our core request-routing loops?