Is there a performance difference between 'let' and 'var' in JavaScript

JavascriptPerformanceScope

Javascript Problem Overview


The difference between these two keywords in terms of scoping has already been thoroughly discussed here, but I was wondering if there is any kind of performance difference between the two, and if so, is it negligible, or at what point would it become significant?

Javascript Solutions


Solution 1 - Javascript

After testing this on http://jsperf.com, I got the following results: jsperf has been down for a while; see the replacing code below.

To check this, I'll use the following performance test based on this answer, which led me to write this function:

/**
 * Finds the performance for a given function
 * function fn the function to be executed
 * int n the amount of times to repeat
 * return array [time for n iterations, average execution frequency (executions per second)]
 */
function getPerf(fn, n) {
  var t0, t1;
  t0 = performance.now();
  for (var i = 0; i < n; i++) {
    fn(i)
  }
  t1 = performance.now();
  return [parseFloat((t1 - t0).toFixed(3)), parseFloat((repeat * 1000 / (t1 - t0)).toFixed(3))];
}

var repeat = 100000000;
var msg = '';

//-------inside a scope------------
var letperf1 = getPerf(function(i) {
  if (true) {
    let a = i;
  }
}, repeat);
msg += '<code>let</code> inside an if() takes ' + letperf1[0] + ' ms for ' + repeat + ' iterations (' + letperf1[1] + ' per sec).<br>'

var varperf1 = getPerf(function(i) {
  if (true) {
    var a = i;
  }
}, repeat);
msg += '<code>var</code> inside an if() takes ' + varperf1[0] + ' ms for ' + repeat + ' iterations (' + varperf1[1] + ' per sec).<br>'

//-------outside a scope-----------

var letperf2 = getPerf(function(i) {
  if (true) {}
  let a = i;
}, repeat);
msg += '<code>let</code> outside an if() takes ' + letperf2[0] + ' ms for ' + repeat + ' iterations (' + letperf2[1] + ' per sec).<br>'

var varperf2 = getPerf(function(i) {
  if (true) {}
  var a = i;
}, repeat);
msg += '<code>var</code> outside an if() takes ' + varperf1[0] + ' ms for ' + repeat + ' iterations (' + varperf1[1] + ' per sec).<br>'

document.getElementById('out').innerHTML = msg

<output id="out" style="font-family: monospace;white-space: pre-wrap;"></output>

After testing this in Chrome and Firefox, this shows that let is faster than var, but only when inside a different scope than the main scope of a function. In the main scope, var and let are roughly identical in performance. In IE11 and MS Edge, let and var are roughly equal in performance in both cases.

Press the big blue button to see for yourself in your favourite browser.

Currently let has support from only newer browsers, but older browsers are still being used relatively much, which would be a reason to generally not use it yet. If you want to use it somewhere where older browsers wouldn't function otherwise, there should be no problem with it.

Edit: revamped answer since jsperf is not working (see revision history for old version).

Solution 2 - Javascript

FYI; After Chrome v60, no further regressions have cropped up. var and let are neck and neck, with var only ever winning by less than 1%. Real world scenarios sometimes give var an advantage due to hoisting and re-use, but at that point you're comparing apples to oranges, as let is intended to allow you to avoid that behavior because the semantics are different.

[Benchmark][1]. Firefox, IE and Edge like let just fine.

[1]: http://jsperf.com/let-vs-var-performance/50 "let vs. var" [2]: https://i.stack.imgur.com/mxF8T.png [3]: https://jsfiddle.net/3jp8Lufm/15/

Solution 3 - Javascript

Inside loops let is significantly slower see: https://jsperf.com/let-vs-var-loop

838,602 ±0.77% 61% slower

(function() {

  "use strict";
  var a=0;
  for(let i=0;i<100;i++) {
    a+=i;
  }
})();

vs.

2,136,387 ±1.09% fastest

(function() {

  "use strict";
  var a=0;
  for(var i=0;i<100;i++) {
    a+=i;
  }
})();

This is because when using let, for every loop iteration the variable is scoped. example:

for (let i = 0; i < 10 ; i++) {
    setTimeout(function() { console.log(i); }, 100 * i);
}

yields to

0,1,2,3,4,5,6,7,8,9

using var yields to

10,10,10,10,10,10,10,10,10,10

If you want to have the same result, but using var you have to use an IIFE:

for (var i = 0; i < 10; i++) {
  // capture the current state of 'i'
  // by invoking a function with its current value
  (function(i) {
    setTimeout(function() { console.log(i); }, 100 * i);
  })(i);
}

which on the other hand is significantly slower than using let.

Solution 4 - Javascript

$ node --version
v6.0.0
$ node
> timeit = (times, func) => {
     let start = (new Date()).getTime();
     for (let i = 0; i < times; i++) {
       func();
     };
     return (new Date()).getTime() - start;
   };
[Function]
> timeit(1000000, () => {
     let sum = 0;  // <-- here's LET
     for (let i = 0; i < 1000; i++) {
       sum += i;
       if (sum > 1000000) { sum = 0; }
     }
     return sum;
   })
12144
> timeit(1000000, () => {
     var sum = 0;  // <-- here's VAR
     for (let i = 0; i < 1000; i++) {
       sum += i;
       if (sum > 1000000) { sum = 0; }
     }
     return sum;
   })
2459

Same scope (function), same code, 5 times difference. Similar results in chrome 49.0.2623.75.

Solution 5 - Javascript

I remade dchekmarev's functions, here are my results.

Tested on Windows 10 x64 (version 1909), XAMPP, Firefox 84.0.2

Time in miliseconds:

  • var: let:
  • 1622 1614
  • 1628 1653
  • 1872 1859
  • 1594 1631
  • 1614 1733
  • 1661 1918
  • 1606 1584
  • 1698 1644
  • 1648 1903
  • 1602 1743

The results are ambiguous, but in most cases var seems a little bit faster

function varTime(times)
{
    var start = (new Date()).getTime();
    var sum = 0; 
     for (var i = 0; i < times; i++) {
        for (var j = 0; j < 1000; j++) {
            sum += j;
            if (sum > 1000000) { sum = 0; }
        }
     };
     console.log('var:', (new Date()).getTime() - start, ' ms');
     return sum;
}

function letTime(times)
{
    let start = (new Date()).getTime();
    let sum = 0; 
     for (let i = 0; i < times; i++) {
        for (let j = 0; j < 1000; j++) {
            sum += j;
            if (sum > 1000000) { sum = 0; }
        }
     };
     console.log('let:', (new Date()).getTime() - start, ' ms');
     return sum;
}

const times = 1000000;

const bla1 = letTime(times);
const bla2 = varTime(times);

Solution 6 - Javascript

var: Declare a variable, value initialization optional. Let is faster in outside scope.

let: Declare a local variable with block scope. Let is a little bit slow in inside loop.

Ex:

var a;
a = 1;
a = 2; //re-intilize possibe
var a = 3; //re-declare
console.log(a); //3

let b;
b = 5;
b = 6; //re-intilize possibe
// let b = 7; //re-declare not possible
console.log(b);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNickolaiView Question on Stackoverflow
Solution 1 - JavascriptJoeytje50View Answer on Stackoverflow
Solution 2 - JavascriptTylerY86View Answer on Stackoverflow
Solution 3 - JavascriptGregor DView Answer on Stackoverflow
Solution 4 - JavascriptdchekmarevView Answer on Stackoverflow
Solution 5 - JavascriptooziefixerView Answer on Stackoverflow
Solution 6 - JavascriptSrikrushnaView Answer on Stackoverflow