Introduction
For many years, var was the only way to declare a variable in JavaScript. With the introduction of ES6 (ECMAScript 2015), two new keywords, let and const, were added, providing more control over variable scope and behavior. Understanding the differences between these three is crucial for writing modern, maintainable, and bug-free JavaScript.
This guide will compare var, let, and const based on their scope, hoisting, and reassignment rules.
1. Scope
Scope determines where a variable is accessible in your code.
var: Function Scope
Variables declared with var are function-scoped. This means they are only accessible within the function they are declared in. If declared outside any function, they have a global scope.
function myFunction() {
if (true) {
var myVar = "Hello from var";
}
console.log(myVar); // "Hello from var" - Accessible here
}
myFunction();
// console.log(myVar); // ReferenceError: myVar is not defined - Not accessible here
Notice that myVar is accessible outside the if block. This is because var does not respect block scope ({...}), which can lead to unexpected behavior.
let and const: Block Scope
Variables declared with let and const are block-scoped. They are only accessible within the block (i.e., inside the curly braces {...}) in which they are defined.
function anotherFunction() {
if (true) {
let myLet = "Hello from let";
const myConst = "Hello from const";
console.log(myLet); // Accessible
console.log(myConst); // Accessible
}
// console.log(myLet); // ReferenceError: myLet is not defined
// console.log(myConst); // ReferenceError: myConst is not defined
}
anotherFunction();
This is much more intuitive and similar to how variables work in many other programming languages. It helps prevent bugs by limiting the variableโs lifecycle to the block where itโs needed.
2. Hoisting
Hoisting is JavaScriptโs behavior of moving declarations to the top of their scope before code execution.
var: Hoisted and Initialized
var variables are hoisted to the top of their scope and are initialized with a value of undefined.
console.log(hoistedVar); // undefined (No error)
var hoistedVar = "I am hoisted";
console.log(hoistedVar); // "I am hoisted"
This means you can access a var variable before itโs declared without getting an error, though its value will be undefined.
let and const: Hoisted but Not Initialized
let and const variables are also hoisted, but they are not initialized. Accessing them before the declaration results in a ReferenceError. The period from the start of the block to the declaration is called the Temporal Dead Zone (TDZ).
// console.log(hoistedLet); // ReferenceError: Cannot access 'hoistedLet' before initialization
let hoistedLet = "I am hoisted too";
// console.log(hoistedConst); // ReferenceError: Cannot access 'hoistedConst' before initialization
const hoistedConst = "So am I";
This behavior prevents you from accidentally using a variable before its value is assigned, making the code more robust.
3. Reassignment
This is the primary difference between let and const.
var and let: Can be Reassigned
Variables declared with var or let can be updated or reassigned.
var myVarVariable = "First value";
myVarVariable = "New value"; // Allowed
let myLetVariable = "First value";
myLetVariable = "New value"; // Allowed
const: Cannot be Reassigned
Variables declared with const (short for constant) must be initialized at the time of declaration and cannot be reassigned a new value.
const myConstVariable = "This value is constant";
// myConstVariable = "Trying to change"; // TypeError: Assignment to constant variable.
Important Note for Objects and Arrays:
When you declare an object or array with const, it means the reference to that object/array is constant, not its content. You can still modify the properties of the object or the elements of the array.
const myObj = { name: "Alice" };
myObj.name = "Bob"; // This is allowed!
console.log(myObj.name); // "Bob"
const myArray = [1, 2, 3];
myArray.push(4); // This is also allowed!
console.log(myArray); // [1, 2, 3, 4]
// But you cannot reassign the variable itself
// myObj = { name: "Charlie" }; // TypeError
// myArray = [5, 6]; // TypeError
Summary and Best Practices
| Keyword | Scope | Hoisting | Reassignment | Redeclaration (in same scope) |
|---|---|---|---|---|
var |
Function | Hoisted and initialized to undefined |
Yes | Yes |
let |
Block | Hoisted, but not initialized (TDZ) | Yes | No |
const |
Block | Hoisted, but not initialized (TDZ) | No | No |
Here are the modern JavaScript best practices for variable declaration:
- Use
constby default: This makes your code more predictable by preventing accidental reassignments. It signals that the variableโs identifier will not be reassigned. - Use
letonly when you know you need to reassign the variable: This is typically for loop counters or variables that need to be updated within a block. - Avoid using
var: There is generally no reason to usevarin modern JavaScript (ES6+). Its function-scoping and hoisting behavior can lead to bugs thatletandconstwere designed to prevent.
By following these rules, you will write clearer, more reliable, and easier-to-debug JavaScript code.
Leave a comment