0

In below example, why the var takes long time than let in for loop ? I did some research on this and found that the var define variable globally because of functional scope and let define variable in block scope. that's why 'var' takes long time than 'let' but still not able to find the practically understanding about why it is so ?

console.time('letCounter');
for (let letCounter = 0; letCounter < 10500; letCounter++) {
    console.log('letCounter', letCounter);
}
console.timeEnd('letCounter');
// 598.838134765625ms

console.time('varCounter');
for (var varCounter = 0; varCounter < 10500; varCounter++) {
    console.log('varCounter', varCounter);
}
console.timeEnd('varCounter');
// 656.56494140625ms
Shubham
  • 1,163
  • 2
  • 12
  • 36
  • 1
    These questions ask the opposite: [Why is let slower than var in a for loop in nodejs?](https://stackoverflow.com/questions/37792934) and [javascript 'let' and 'var' in for-loops](https://stackoverflow.com/questions/43847863) – adiga Jul 03 '19 at 06:28

1 Answers1

1

The problem with global variables is that the compiler cannot know if the content is going to be accessed by "external" functions (i.e. in which the body is not known at compile time).

For example console.log could (in theory) change varCounter if it's a global variable. The variable must then be stored in a full Javascript slot (able to contain strings, arrays, objects) and then read back from that to do the increment.

If the variable is instead local no access is possible if the var is not captured and therefore the variable itself can be optimized away and the loop could just detect the pattern and increment a 32-bit integer as the index, without allocating a full Javascript slot.

If the variable is a function-local var however things are different because that too cannot be accessed by an external function. In this case execution could even be faster with var than with let if the compiler is not smart enough: the reason is that if in the body the variable is potentially captured by a closure, a new closure cell must be allocated at each iteration. That doesn't happen with var because the scope is the whole function (not the body of the for loop):

 x = [];
 for (let i=0; i<10; ++) {
     x.push(()=>i);
 }
 console.log(x[4]()); // Shows 4

changing let to var in the above loop you'll get 10 instead, because all closures are capturing the same var cell.

6502
  • 112,025
  • 15
  • 165
  • 265
  • Thanks for your explanation. "For example console.log could (in theory) change varCounter if it's a global variable. The variable must then be stored in a full Javascript slot (able to contain strings, arrays, objects) and then read back from that to do the increment." but could you please explain this part ? – Shubham Jul 03 '19 at 06:48
  • @Shubham: Javascript is dynamically typed and a variable can contain any object type. This means that variables are indeed pointers to heap-allocated objects (or must be able to contain also pointers in certain cases). For each operation on a variable a type check must be done to decide what operations are needed and this is slower than just incrementing a number. If the compiler sees that the variable is used only in the loop (no externa access) then the generated machine code can in theory use instead just a CPU register for the index. This is what is meant with "optimizing out a variable". – 6502 Jul 03 '19 at 06:59