Learn the differences between var, let, and const in JavaScript. Master scoping, hoisting, and immutability with real-world examples.
JavaScript is one of the most popular and versatile programming languages in the world. As a frontend developer, understanding how variables work is fundamental to writing efficient and bug-free code. The way JavaScript handles variables can have a huge impact on your application’s behavior. In this article, we’ll dive deep into the differences between var
, let
, and const
—the three ways to declare variables in JavaScript. By the end of this article, you’ll understand how each works, their differences, and when to use them in real-world scenarios, especially in frameworks like React or TypeScript.
In JavaScript, variables are containers for storing data. However, the way these variables are declared and scoped can vary depending on which keyword you use. The three main keywords for declaring variables are var
, let
, and const
. Understanding the differences between these can help prevent bugs, especially in complex applications like those built with React or when using modern JavaScript features.
let
and const
Historically, JavaScript only had one way to declare variables—var
. However, with the introduction of ES6 (ECMAScript 2015), let
and const
were introduced to improve the way JavaScript handles variable scoping and immutability. While var
is still widely used, the modern best practice is to prefer let
and const
for declaring variables.
var
- The Old School of JavaScriptvar
Before ES6, var
was the only way to declare a variable. Even though var
is still valid JavaScript, it has some quirks that can lead to bugs, especially in large, complex applications. Here’s a breakdown of how var
behaves:
var
is scoped to the nearest function, not the block of code in which it is declared.var
declarations are hoisted to the top of the function or global scope, which means they are initialized with undefined
before the execution of the code begins. This can lead to some confusing behavior.var
and Hoistingfunction testVar() {
console.log(myVar); // undefined
var myVar = 'Hello, World!';
console.log(myVar); // 'Hello, World!'
}
testVar();
In the example above, even though the variable myVar
is used before it is declared, JavaScript does not throw an error. Instead, it returns undefined
because var
is hoisted, and the variable is initialized at the top of the function.
var
The main issue with var
is that it allows variables to be accidentally overwritten, or worse, misused in different scopes. Because var
is function-scoped rather than block-scoped, this can lead to unexpected behavior in loops or conditionals.
for (var i = 0; i < 3; i++) {
console.log(i); // prints 0, 1, 2
}
console.log(i); // prints 3, because `i` is accessible outside the loop
In this case, i
is accessible outside the loop because var
is function-scoped, not block-scoped.
let
- The Modern Approachlet
Introduced in ES6, let
allows you to declare variables that are scoped to the nearest block, statement, or expression. This provides more predictable behavior, especially in loops and conditionals. Here’s how let
works:
let
is scoped to the nearest block (enclosed by curly braces {}
), whether it’s a function, loop, or if statement.let
are hoisted, but they are not initialized until the code execution reaches the let
declaration. This leads to a temporal dead zone (TDZ), which prevents accessing the variable before it’s declared.let
and Block Scopingfunction testLet() {
if (true) {
let myLet = 'Hello, World!';
console.log(myLet); // 'Hello, World!'
}
console.log(myLet); // ReferenceError: myLet is not defined
}
testLet();
In the example above, myLet
is scoped to the if
block and cannot be accessed outside of it. This is a significant improvement over var
, where the variable would have been accessible outside the block.
let
Even though let
is much safer than var
, it still requires attention to detail. For instance, re-declaring a variable within the same scope is not allowed:
let myLet = 'First Declaration';
let myLet = 'Second Declaration'; // SyntaxError: Identifier 'myLet' has already been declared
const
- Constants in JavaScriptconst
const
is used to declare variables that are constant, meaning their values cannot be reassigned after they are initialized. Like let
, const
is also block-scoped. However, there is one key difference: once a variable is assigned a value with const
, that value cannot be changed.
let
, const
is scoped to the nearest block.const
variable cannot be reassigned. However, if the value is an object or array, the contents of the object or array can still be modified (but the reference cannot).const
const myConst = 'Hello, World!';
myConst = 'New Value'; // TypeError: Assignment to constant variable
In the example above, trying to reassign a value to myConst
will result in an error because it is a constant.
const
If the value assigned to const
is an object, the object itself is mutable, but the reference cannot be changed.
const myObj = { name: 'John' };
myObj.name = 'Jane'; // This is allowed
myObj = { name: 'Mike' }; // TypeError: Assignment to constant variable
This behavior often confuses developers new to const
, as they may expect the object itself to be immutable.
var
, let
, and const
Feature | var |
let |
const |
---|---|---|---|
Scope | Function-scoped | Block-scoped | Block-scoped |
Hoisting | Hoisted (initialized to undefined ) |
Hoisted (TDZ) | Hoisted (TDZ) |
Reassignable | Yes | Yes | No (immutable reference) |
Redeclarable | Yes | No | No |
var
, let
, and const
Use var
: Although var
is generally discouraged due to its confusing scoping rules, you may still encounter legacy code or libraries where it’s used. If you’re working with older codebases, understanding var
is essential.
Use let
: Use let
when the value of the variable might change later. It’s perfect for loops, conditionals, and situations where reassignment is required.
Use const
: Use const
for values that should not be reassigned. This is ideal for variables that hold references to immutable objects or values, ensuring that they are not accidentally modified.
let
and const
One common pitfall for developers is trying to re-declare a variable using let
or const
in the same scope. Unlike var
, this will throw a SyntaxError.
let x = 10;
let x = 20; // SyntaxError: Identifier 'x' has already been declared
Another issue developers face is misunderstanding block scope. Remember, let
and const
are confined to the block in which they are declared, while var
can leak outside the block.
if (true) {
var foo = 'bar';
let bar = 'foo';
}
console.log(foo); // 'bar' (accessible globally)
console.log(bar); // ReferenceError: bar is not defined
const
by default: For most variables, use const
unless you explicitly need to reassign the variable. This helps avoid accidental reassignments.let
when reassigning is needed: If the value of the variable will change, use let
. Avoid var
due to its scoping issues.In summary, the introduction of let
and const
in ES6 significantly improved the way we handle variables in JavaScript. While var
still has its place in legacy code, modern JavaScript development heavily relies on let
and const
for better control and predictability of variable scoping and immutability.
var
with caution and primarily in legacy codebases.const
for all variables unless reassignment is necessary.let
for variables that require reassignment, especially in loops or conditional blocks.