A JavaScript variable is typically created using one of three keywords: var, let, or const. Each behaves differently in terms of scope, hoisting, and mutability, though they all might function very similarly. This article breaks down the differences between these keywords in simple terms so that you can write cleaner and more secure code
1. var: The Old Legacy Variable Declaration
Scope: Function Scope
- Variables declared with var are function scoped (or globally scoped if defined outside a function).
- They're accessible from anywhere within the function where they are defined.
Example:
function exampleVar() {
if (true) {
var x = 10;
}
console.log(x); // 10 (not limited to the block)
};
Hoisting
- var declarations are hoisted to the top of the containing function and initialized with undefined.
- This can lead to unexpected behavior if not taken into account.
console.log(y); // undefined (no error)
var y = 5;
Redeclaration and Reassignment
- var allows redeclaration and reassignment:
var z = 1;
var z = 2; // No error
z = 3; // Reassignment allowed
Drawbacks
- No block scoping: Variables leak into blocks like loops or conditionals.
- Prone to bugs: May cause unintended side effects from hoisting and redeclaration.
2. let: The Modern Block-Scoped Variable
Block-Level Scope
- let variables are block scoped: they only exist within {} like loops, conditionals, or function bodies.
- Safer and more predictable than var.
Example:
function exampleLet() {
if (true) {
let a = 20;
console.log(a); // 20
}
console.log(a); // ReferenceError: a is not defined
}
Hoisting and the Temporal Dead Zone (TDZ)
- let declarations are hoisted but not initialized.
- Accessing them before declaration results in ReferenceError.
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 5;
Reassignment and Redeclaration
- let allows reassignment but not redeclaration.
let c = 10;
c = 20; // Allowed
let c = 30; // SyntaxError: Identifier 'c' has already been declared
3. const: Constants for Immutable Values
Scope: Like let, Block Scoped
- Variables created with const are block scoped, meaning they can only be accessed within their defining block.
- They cannot be reassigned after initialization.
Example:
const PI = 3.14;
PI = 3.14159; // TypeError: Assignment to constant variable
Immutable ≠ Unchangeable Values
- With const, you cannot reassign values, but you can mutate them.
- Objects and arrays declared with const can have their properties/methods altered.
const person = { name: "Alice" };
person.name = "Bob"; // Valid
person = { name: "Charlie" }; // TypeError (reassignment not allowed)
Hoisting and the Temporal Dead Zone (TDZ)
- Similar to let, const declarations are also hoisted and trigger the TDZ.
Key Differences Summary
Feature | var | let | const |
---|---|---|---|
Scope | Function/Global | Block | Block |
Hoisting | Yes (initialized) | Yes (not initialized) | Yes (not initialized) |
Redeclaration | Allowed | Not allowed | Not allowed |
Reassignment | Allowed | Allowed | Not allowed |
TDZ | No | Yes | Yes |
When to Use Each
-
const (Recommended):
- For values that shouldn’t be reassigned (e.g., configuration objects, API keys).
- Used by default unless reassignment is needed.
-
let:
- When a variable requires reassignment (e.g., loop counters, state changes).
- More robust than var with block scope.
-
var:
- Rarely needed in modern JavaScript. Use only in legacy projects or specific cases.
Common Mistakes
Slipping into Global Variable Declarations
function badPractice() {
for (var i = 0; i < 5; i++) { /*... */ }
console.log(i); // 5 (leaked outside loop)
}
Fix: Use let for block scoping.
Issues Related to TDZ
let greeting = "Hello";
if (true) {
console.log(greeting); // ReferenceError (TDZ)
let greeting = "Hi";
}
Fix: Define variables at the top of their scopes.
Misunderstandings of const’s Immutability
const arr = [1, 2];
arr.push(3); // Valid (array contents changed)
arr = [4, 5]; // TypeError (reassignment not allowed)
Best Practices
- Use const by default, and let only when reassignment is necessary.
- Avoid var , except for maintaining legacy code.
- Declare variables at the top to avoid TDZ errors.
- Use linters like ESLint to enforce best practices.
Conclusion
Understanding var, let, and const is crucial for writing secure JavaScript. Embracing block scope (let
/const) and immutability (const) reduces bugs and makes your code easier to debug and maintain.Key takeaways:
- const prevents reassignment but not mutation.
- let and const are the modern standard in JavaScript.
No comments