The differences between let
and var
in JavaScript are crucial for understanding variable scoping and behavior:
1. Scope
var
: Function-scoped. Accessible throughout the entire function or globally if declared outside a function.
function exampleVar() {
if (true) {
var x = 10;
}
console.log(x); // 10 (accessible outside the block)
}
let
: Block-scoped. Accessible only within the block ({}
) where it’s defined.
function exampleLet() {
if (true) {
let y = 20;
}
console.log(y); // ReferenceError: y is not defined
}
2. Hoisting
var
: Hoisted to the top of its scope and initialized withundefined
.
console.log(a); // undefined
var a = 5;
let
: Hoisted but not initialized (Temporal Dead Zone). Accessing it before declaration causes an error.
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 10;
3. Redeclaration
var
: Allows redeclaring the same variable in the same scope.
var c = 1;
var c = 2; // No error
let
: Throws an error if redeclared in the same scope.
let d = 3;
let d = 4; // SyntaxError: Identifier 'd' has already been declared
4. Loop Behavior
var
: Shares the same variable across loop iterations, leading to unexpected behavior in closures.
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // Outputs 3, 3, 3
}
let
: Creates a new variable per iteration, fixing closure issues.
for (let j = 0; j < 3; j++) {
setTimeout(() => console.log(j), 100); // Outputs 0, 1, 2
}
5. Global Object Property
var
: Declaring globally adds the variable as a property on thewindow
object (in browsers).
var globalVar = "I'm global!";
console.log(window.globalVar); // "I'm global!"
let
: Does not become a property of the global object.
let globalLet = "I'm scoped!";
console.log(window.globalLet); // undefined
Summary Table
Feature | var | let |
---|---|---|
Scope | Function-scoped | Block-scoped |
Hoisting | Initialized as undefined | Not initialized (TDZ) |
Redeclaration | Allowed | Not allowed |
Loop Behavior | Single variable per loop | New variable per iteration |
Global Property | Added to window | Not added to window |
Best Practices
- Use
let
by default for clearer scoping and to avoid bugs. - Avoid
var
unless maintaining legacy code or needing function-scoped hoisting intentionally.