let vs var in JavaScript: what's the difference?
By Flavio Copes
Learn how let and var differ in JavaScript: let is block scoped and has a temporal dead zone, var is function scoped and attaches to the global object.
In modern JavaScript we have 3 ways to declare a variable and assign it a value:
constletvar
When working with variables in JavaScript, I always default to using const. It guarantees the value can’t be reassigned, and so it’s safer to use.
But when I do need to redeclare a variable later on, I always use let.
I haven’t used var in years, and to me it’s just there for backwards compatibility purposes, and I always raise an eyebrow when I see it used.
Why?
First, let has sensible scoping.
The same scoping that is used in more or less all popular programming languages, block scoping, dictates that variables declared using let are scoped to the nearest block.
var instead is a bit more weird, as it has function scoping, which means that variables declared using var are scoped to the nearest function.
This has practical implications. For example, a variable is declared inside an if or used as the for loop iterator. Using let makes it local to those 2 blocks. Using var, however, allows the variable to be available outside of that block, which might lead to bugs.
Here is var leaking out of an if:
if (true) {
var city = 'Rome'
}
console.log(city) // 'Rome'
The same pattern with let keeps the variable inside the block:
if (true) {
let city = 'Rome'
}
console.log(city) // ReferenceError: city is not defined
A for loop shows the same gap. With var, the iterator is still there after the loop:
for (var i = 0; i < 3; i++) {
// ...
}
console.log(i) // 3
With let, it is not:
for (let i = 0; i < 3; i++) {
// ...
}
console.log(i) // ReferenceError: i is not defined
Always use the tool that gives you the least amount of power, to make sure you have maximum control over it. With great power comes great responsibility.
Another reason to prefer let is hoisting. let and const bindings are hoisted to the top of the block, but they stay uninitialized until the declaration runs. That gap is the temporal dead zone. If you read the variable before that line, you get a ReferenceError.
var is also hoisted, but it is initialized to undefined right away, so you can read it before the declaration and just get undefined. Weird, right?
console.log(brand) // undefined
var brand = 'Ford'
The same code with let throws:
console.log(brand) // ReferenceError: Cannot access 'brand' before initialization
let brand = 'Ford'
I cover more of this in JavaScript variables and scope.
Third reason: when you declare a let variable with the same name as one that already exists in the same scope, you get an error.
var lets you redeclare the same name in the same scope:
var count = 1
var count = 2
console.log(count) // 2
let does not:
let count = 1
let count = 2 // SyntaxError: Identifier 'count' has already been declared
Finally, another big difference: if you declare a var variable outside of any function, it’s assigned to the global object, which means window inside the browser. let does not work in this way; the variable is available, but not attached to the global object, and so it’s not reachable from outside of your file.
In a browser script:
var language = 'JavaScript'
console.log(window.language) // 'JavaScript'
let year = 2026
console.log(window.year) // undefined
console.log(year) // 2026
language is both a global variable and a property on window. year is still available in that script, but it is not a window property.
Want me to talk about your product? You can sponsor this site.
Related posts about js: