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 withconstfor every variable. Only change toletwhen you discover you need to reassign it. This approach makes your code more predictable because readers know thatconstvariables will not change, reducing cognitive load when understanding the code.
Key Takeaways
- Use
constby default,letwhen reassignment is needed, and never usevarin modern JavaScript. varis function-scoped and hoisted;letandconstare block-scoped with a Temporal Dead Zone.constprevents reassignment of the variable, but object properties and array elements can still be modified.- Block scoping with
letfixes the classic closure-in-loop bug that affectsvar. - Follow naming conventions: camelCase for variables and functions, UPPER_SNAKE_CASE for true constants.