A visual summary explaining the main topic of this post: JavaScript Variables: The Difference Between var, let, and const

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:

  1. Use const by default: This makes your code more predictable by preventing accidental reassignments. It signals that the variableโ€™s identifier will not be reassigned.
  2. Use let only 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.
  3. Avoid using var: There is generally no reason to use var in modern JavaScript (ES6+). Its function-scoping and hoisting behavior can lead to bugs that let and const were designed to prevent.

By following these rules, you will write clearer, more reliable, and easier-to-debug JavaScript code.

Professional Depth Check

For JavaScript Variables: The Difference Between var, let, and const, the practical standard is not whether the reader can repeat one instruction once. Treat the topic as a reproducible debugging procedure: verify runtime environment, exact error boundary, minimal reproduction, and rollback path before drawing a conclusion. The result should be written as a small decision record, because future readers need to know which fact was observed, which assumption was used, and which condition would change the answer.

Evidence That Makes the Guidance Reliable

Use objective evidence before changing a workflow. Good evidence includes full command output, version numbers, changed files, and expected versus actual behavior. If two pieces of evidence conflict, keep the conflict visible instead of smoothing it over. For example, a successful quick fix is still weak evidence if the same input, account, dependency, or device state has not been tested again. A durable article should help the reader distinguish a confirmed fix from a plausible fix.

Review Table

Review Item What To Confirm Why It Matters
Scope The exact case covered by this article Prevents over-applying the advice
Baseline The state before any change Makes rollback and comparison possible
Change The smallest action taken Reduces hidden side effects
Result The observed output after the change Separates evidence from expectation
Recheck When to revisit the conclusion Keeps the post accurate over time

Continue with these related posts from the same topic area.

Leave a comment