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: