beginner Step 2 of 20

Variables - var, let, const

JavaScript Programming

Variables - var, let, const

Variables in JavaScript store data values that your program can use and manipulate. JavaScript provides three keywords for declaring variables: var, let, and const. Understanding the differences between them — particularly their scoping rules and mutability — is crucial for writing bug-free JavaScript code. Modern JavaScript (ES6+) introduced let and const as improvements over var, and they should be your default choices in all new code.

var, let, and const

// var — function-scoped, can be redeclared (legacy)
var name = "Alice";
var name = "Bob";     // No error — redeclaration allowed
name = "Charlie";     // Reassignment allowed

// let — block-scoped, cannot be redeclared
let age = 30;
// let age = 31;      // SyntaxError — cannot redeclare
age = 31;             // Reassignment is fine

// const — block-scoped, cannot be reassigned
const PI = 3.14159;
// PI = 3.14;         // TypeError — cannot reassign
// const PI = 3;      // SyntaxError — cannot redeclare

// const with objects and arrays — the REFERENCE is constant, not the content
const user = { name: "Alice", age: 30 };
user.age = 31;         // This works! Modifying properties is allowed
// user = {};          // TypeError — cannot reassign the variable

const colors = ["red", "green"];
colors.push("blue");   // This works! ["red", "green", "blue"]
// colors = [];        // TypeError — cannot reassign

Scoping Differences

// var is function-scoped
function varExample() {
    if (true) {
        var x = 10;
    }
    console.log(x);  // 10 — var leaks out of the if block!
}

// let and const are block-scoped
function letExample() {
    if (true) {
        let y = 20;
        const z = 30;
    }
    // console.log(y);  // ReferenceError — y is not defined
    // console.log(z);  // ReferenceError — z is not defined
}

// Loop scoping — a classic gotcha
// With var (buggy)
for (var i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 100);
}
// Prints: 3, 3, 3 (all reference the same 'i')

// With let (correct)
for (let j = 0; j < 3; j++) {
    setTimeout(() => console.log(j), 100);
}
// Prints: 0, 1, 2 (each iteration has its own 'j')

Hoisting

JavaScript moves variable and function declarations to the top of their scope before execution. This behavior is called hoisting. However, var, let, and const are hoisted differently.

// var is hoisted and initialized to undefined
console.log(a);  // undefined (not an error!)
var a = 5;

// let and const are hoisted but NOT initialized (Temporal Dead Zone)
// console.log(b);  // ReferenceError: Cannot access 'b' before initialization
let b = 10;

// Function declarations are fully hoisted
sayHello();  // Works! "Hello!"
function sayHello() {
    console.log("Hello!");
}

// Function expressions are NOT fully hoisted
// greet();  // TypeError: greet is not a function
var greet = function() {
    console.log("Hi!");
};

Best Practices

// Rule 1: Use const by default
const API_URL = "https://api.example.com";
const MAX_RETRIES = 3;
const config = { debug: true, version: "1.0" };

// Rule 2: Use let only when you need to reassign
let counter = 0;
counter++;

let currentUser = null;
currentUser = await fetchUser();

// Rule 3: Never use var in modern code
// var has confusing scoping rules and is error-prone

// Rule 4: Declare variables at the top of their scope
function processData(items) {
    const results = [];
    let total = 0;

    for (const item of items) {
        const processed = transform(item);
        total += processed.value;
        results.push(processed);
    }

    return { results, total };
}

// Naming conventions
const firstName = "Alice";          // camelCase for variables
const MAX_SIZE = 100;               // UPPER_SNAKE for constants
const isValid = true;               // Boolean: is/has/can prefix
const getUserName = () => "Alice";  // camelCase for functions
Pro tip: Start with const for every variable. Only change to let when you discover you need to reassign it. This approach makes your code more predictable because readers know that const variables will not change, reducing cognitive load when understanding the code.

Key Takeaways

  • Use const by default, let when reassignment is needed, and never use var in modern JavaScript.
  • var is function-scoped and hoisted; let and const are block-scoped with a Temporal Dead Zone.
  • const prevents reassignment of the variable, but object properties and array elements can still be modified.
  • Block scoping with let fixes the classic closure-in-loop bug that affects var.
  • Follow naming conventions: camelCase for variables and functions, UPPER_SNAKE_CASE for true constants.