Both let
and var
allow you to create variables in JavaScript. The main differences between them are
scope, hoisting and closures.
JavaScript scopes in the context of var
and let
The variables declared with the var
keyword can be global, while the ones declared with let
can’t.
It’s important if you try to create a global variable in the browser and then access it later as a property
of the object window
.
var x = 17;
let y = 25;
console.log(window.x); // 17
console.log(window.y); // undefined
Variables declared with var
don’t have block scope, it’s only available to the variables declared with let
.
It’s very dangerous as you may accidentally overwrite something you didn’t mean to.
var i = 0;
let j = 0;
if (i === 0) {
var i = 'overwritten!';
}
if (j === 0) {
let j = 'overwritten!';
}
console.log(i); // overwritten!
console.log(j); // 0
Hoisting in JavaScript
Hoisting in JS is the process or “lifting” the variables up to the top of the scope before they’re used.
It can be best described with the code example.
console.log(message); // undefined
var message = 'hello';
Once you run this code, you’ll see the value undefined
logged to the console.
However, if you change the variable declaration from var
to let
, the result will be completely different.
console.log(message); // ReferenceError: Cannot access 'message' before initialization
var message = 'hello';
In this case you’ll get an error ReferenceError: Cannot access 'message' before initialization
.
This is a useful error that can prevent a lot of bugs as there’s no point in trying to access something before
initializing it.
Closure behaviour for var
and let
Using let
allows you to capture the present value of the variable in JavaScript closure.
With var
you wouldn’t be able to do that.
The best example would be a for
loop with a setTimeout
.
for(var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1000);
}
If you expected to see the values 0
, 1
, and 2
to be logged to console after a one second delay, I have bad news
for you. It’d not that’s going to happen.
Instead, you’ll see the number 3
logged three times to the console.
The problem? The scoping issue with the var
keyword doesn’t allow JavaScript to capture the present value of
the counter i
when you set the timeout on each iteration of the loop.
The good news is that it’s easily fixable with let
.
for(let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1000);
}
Now, you’ll see the values 0
, 1
, and 2
in the console as expected.
As a conclusion, I suggest you always use let
over var
unless you’re working in some ancient legacy
environment that doesn’t support declaring variables with let
.