78

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?

3

6 Answers 6

72

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).

23
  • 1
    @Nickolai If this was the answer you were looking for, please mark it as accepted by clicking the outlined checkmark just to the left of this answer's contents, at the top. That will show to others that this question has been answered, and in case others might end up on this page it'll also show them that this answer was what you were looking for. Marking it as accepted will also give both the the asker (you) and the answerer some reputation points, which is a nice gesture to show your appreciation.
    – Joeytje50
    Commented Jan 30, 2014 at 21:45
  • 2
    Chrome doesn't support let, and in Firefox you should provide type attribute <script type="application/javascript;version=1.7">
    – Givi
    Commented Jan 30, 2014 at 22:46
  • 1
    Current versions of Chrome do support let in strict mode with experimental JS features flag enabled (chrome://flags/#enable-javascript-harmony). This test works in Chrome and IE11: jsperf.com/let-vs-var-definition/5 IE11 ("Other") seems to handle let well. Chrome on the other hand is much slower with it.
    – Qtax
    Commented May 29, 2014 at 16:57
  • 1
    The results don't agree with the assertion that let is faster. :(
    – TylerY86
    Commented Sep 2, 2015 at 5:47
  • 4
    This test probably isn't testing if let is faster than var in the real world. You have no idea what kind of code the browser is generating. The code is very simple and since the result is never used and the ifs are constant chrome could just as easily deleted all the code for the either. See this for exampes issues with tiny benchmarks. It's C++ but the points it makes are still relevant.
    – gman
    Commented Feb 1, 2017 at 2:00
23

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. Firefox, IE and Edge like let just fine.

10
  • 5
    Just an update; let is still slower than var on Chrome, and equal everywhere else.
    – TylerY86
    Commented Apr 3, 2016 at 22:00
  • 2
    As of Chrome v51.0.2704.84 m (64-bit) ( V8 5.1.281.59) let might be faster than var in all cases now by about 5% with with no loss in var performance, and overall generally higher scores on the same system.
    – TylerY86
    Commented Jun 16, 2016 at 3:38
  • 5
    Chrome 52, let barely still wins: let inside scope x 93,575,363 ops/sec ±2.28% (58 runs sampled), var inside scope x 81,266,031 ops/sec ±1.84% (58 runs sampled), let outside scope x 90,070,266 ops/sec ±1.37% (61 runs sampled), var outside scope x 82,425,646 ops/sec ±1.34% (59 runs sampled)
    – TylerY86
    Commented Aug 7, 2016 at 20:10
  • 5
    As of Chrome 55, let wins inside scope by 21%, var wins outside scope by 55%. What the hell.
    – TylerY86
    Commented Oct 26, 2016 at 17:07
  • 1
    Testing from v60.0.3112.113 64-bit (on Ubuntu 17.10) shows a huge performance boost on both sides for let and var, but var still comes out slightly ahead (on average over many runs). At this point though, the speed difference appears to be negligible.
    – TylerY86
    Commented Sep 5, 2017 at 13:00
10

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.

3
  • 2
    Yup, 60% slower in chrome and node, while FF has no difference. Commented Feb 24, 2017 at 9:58
  • 1
    This answer sends a confusing signal that is not consistent with other answers mostly because it's considering a scenario that is conflating closure performance with var vs let performance. The qualifier in the topic sentence "inside loops" is too general. What this answer actually considers is "closures created in loops". Which is just one specific use case. It doesn't actually address the topic of performance of var vs let alone - which as I understand from other answers is nearly identical, with let being marginally faster.
    – Wyck
    Commented Oct 24, 2019 at 13:32
  • There is no difference now.
    – Donny V.
    Commented Apr 26, 2020 at 2:38
2
$ 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.

1
  • Try it in node with the code from here; jsfiddle.net/3jp8Lufm/11 ; Also, your test is not checking the use of let inside scopes, only on the outside (thus no variable re-use vs. re-creation scenario).
    – TylerY86
    Commented May 31, 2016 at 16:03
1

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);
0

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);

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.