1

I want to understand how and when javascript engines pass values to callback functions, I have tried debugging and looking up online but I am unable to find exact answer, consider the following example:

for(var i = 0; i < 4; i++) {
    console.log("outside callback " + i + " ");

    setTimeout(function test(){
      console.log("inside callback " + i + " ");
    },100);
}

this prints following output

outside callback 0

outside callback 1

outside callback 2

outside callback 3

inside callback 4

inside callback 4

inside callback 4

inside callback 4

If I just change the declaration of i variable using let keyword as follows:

for(let i = 0; i < 4; i++) {
    console.log("outside callback " + i + " ");
    
    setTimeout(function test(){
       console.log("inside callback " + i + " ");
    },100);
}

It results in the following output:

outside callback 0

outside callback 1

outside callback 2

outside callback 3

inside callback 0

inside callback 1

inside callback 2

inside callback 3

When debugging this in Chrome, it shows i in first example as closure scope for test function and block scope in second example.

1
  • 1
    How is the variable scope related to "when javascript engines pass values to callback functions"? Commented Jul 10, 2017 at 12:24

2 Answers 2

2

This relates to a frequently asked question about JavaScript closure inside loops – simple practical example , which goes into detail about why inside call back functions created in a loop, variables declared using var have the values they reached when the loop ended: while they may have held different values when the callback was setup, when the call back is performed, asynchronously, some time later, the loop has long finished and left variables inside a closure with the values they held when the loop completed.

From ECMAScript version 6 onwards, variables declared using let are block scoped and cannot be accessed outside the code block in which they are defined. In addition variables defined in a for loop control statement receive special treatment.

  1. Their scope is that of the for loop body, not the block of code containing the for loop.
  2. A new binding for let variables is created for each iteration of the loop. This means each iteration can have its own set of variable values, held in a lexical environment record created for the iteration, that can be used in a closure and accessed by callback functions defined within the loop.

  3. The value of loop counters in each lexical environment record is designed to make the use of multiple environment records largely transparent:

    for( part1; part2; part3) {
        // loop body code
    }
    
    • In the first iteration, let defined variables within the for statement have the values they would have after executing part1 and part2.
    • In subsequent iterations, they have the values determined by initializing their values in the environment record for the current iteration with those they had at the end of the previous iteration, and then executing part3 and part2 in the for statement above.
    • call back functions declared inside the for loop body access the value of let defined variables held at the end of the iteration in which the call back was set up, excluding side effects of evaluating part3 of the for statement.
Sign up to request clarification or add additional context in comments.

Comments

1

It is actually because of the scope of varaibles declared using let and var, not only the closure property of javascript.

2 Comments

Can you please explain a bit more what happens exactly here
I hope this post explains very clearly about the issue of using global namespace.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.