S

Sajiron

Published on Feb 01, 2025

Understanding the Difference Between var, let, and const in JavaScript

DALL·E 2025-02-01 13.24.10 - An educational illustration comparing var, let, and const in JavaScript. The image should include a structured flowchart or infographic displaying dif.webp

Learn the critical differences between JavaScript’s var, let, and const—scope, hoisting, mutability, and best practices to write clean, bug-free code.

Introduction to JavaScript Variables

JavaScript developers often encounter var, let, and const when declaring variables. While var was traditionally used, let and const were introduced in ES6 (ECMAScript 2015) to address scoping issues and improve code maintainability. Understanding their differences is essential for writing robust and bug-free JavaScript code.

In this guide, we'll explore the key differences between var, let, and const, and provide best practices to optimize your JavaScript projects.

var: var keyword has been present since JavaScript was created. However, it has several drawbacks due to its scoping behavior.

let/const: let/const keywords were introduced in ES6 to provide better block scoping and prevent issues caused by var.

Now, let's discuss the key differences between var, let, and const variables.

1. Variable Scope in JavaScript: var vs. let/const

Variable scope defines where a variable can be accessed.

Function Scope with var

var is function-scoped, meaning var variables are accessible within the function they are defined in, even if declared inside a block (like an if statement).

function foo() {
if (true) {
var x = 20;
}

console.log(x); // Output: 20
}

foo();

Block Scope with let and const

let and const are block-scoped, meaning they are confined to the block ({}) in which they are declared. Typically, this block is the nearest pair of curly braces surrounding the declaration.

function foo() {
if (true) {
let x = 20;
}

console.log(x); // ReferenceError: x is not defined
}

foo();

2. Hoisting: Why var Behaves Differently Compared to let and const

Hoisting is the mechanism by which the JavaScript engine allocates memory for variable declarations at the beginning of their scope before executing the code.

var variables are hoisted to the top of their function or global scope and initialized with undefined, meaning they can be accessed before declaration but will return undefined, which can lead to confusing behavior.

console.log(x); // Output: undefined
var x = 10;

let/const variables are hoisted but not initialized, meaning they exist in a Temporal Dead Zone (TDZ) until their declaration is reached. Accessing them before declaration results in a ReferenceError.

console.log(x); // ReferenceError
let x = 10;

3. Reassigning and Redeclaring Variables

Keyword

Redeclare?

Reassign?

var

✅ Yes

✅ Yes

let

❌ No

✅ Yes

const

❌ No

❌ No

Why avoid var? You can redeclare a variable with var in the same scope without an error.

var count = 5;  
var count = 10; // No error

Safer Code with let and const

let score = 100;  
score = 200; // Allowed

const MAX_USERS = 10;
MAX_USERS = 20; // TypeError

4. Mutability: const Doesn’t Mean Immutable

The const keyword is used to declare constants, but this does not mean the value is immutable. const variables behave like let variables, except they cannot be reassigned after declaration.

const foo = { bar: "a" };  
foo.bar = "b"; // Allowed (mutating content)

foo = { bar: "c" }; // TypeError (reassigning reference)

5. Global Scope and the window Object

In browsers, var in the global scope attaches to the window object, risking naming collisions. let and const stay private:

var globalVar = "I’m global!";  
let privateLet = "I’m not on window";

console.log(window.globalVar); // "I’m global!"
console.log(window.privateLet); // undefined

6. Solving Loop Issues with Block Scoping

A classic var pitfall in loops with closures:

for (var i = 0; i < 3; i++) {  
setTimeout(() => console.log(i)); // Logs 3, 3, 3
}

Fix with let:

for (let j = 0; j < 3; j++) {  
setTimeout(() => console.log(j)); // Logs 0, 1, 2
}

In the first loop (var), there is a single shared i, so by the time setTimeout runs, i is 3 for all iterations. In the second loop (let), each iteration gets a new i, preserving its value when setTimeout executes, resulting in 0, 1, 2.

Summary

Feature

var

let

const

Scope

Function

Block

Block

Hoisting

Yes (initialized as undefined)

Yes (TDZ applies)

Yes (TDZ applies)

Redeclaration

Allowed

Not allowed

Not allowed

Reassignment

Allowed

Allowed

Not allowed

Must be initialized

No

No

Yes

Best Practices for JavaScript Variables

Use const by default for variables that won’t change.

Choose let when reassignment is needed.

Avoid var (legacy, error-prone).

This approach minimizes bugs and aligns with modern JavaScript (ES6+).

Conclusion

By understanding the differences between var, let, and const, developers can write cleaner, more predictable, and less error-prone JavaScript code. As a best practice, prefer const where possible, use let when necessary, and avoid var to minimize potential issues.

For more info: MDN’s var, let, and const