Variables are containers that store data values. In JavaScript, you have three ways to declare them: let, const, and var. Understanding the differences is essential - it's one of the most common interview questions and a source of real bugs in production code.
1let age = 25; // Can be reassigned2const name = "Alice"; // Cannot be reassigned3var score = 100; // Old way - avoid in modern JS45console.log(age); // 256console.log(name); // Alice7console.log(score); // 100
| Feature | let | const | var |
|---|---|---|---|
| Reassignable | ✅ Yes | ❌ No | ✅ Yes |
| Block-scoped | ✅ Yes | ✅ Yes | ❌ No (function-scoped) |
| Hoisted | ✅ (TDZ) | ✅ (TDZ) | ✅ (initialized as undefined) |
| Redeclarable | ❌ No | ❌ No | ✅ Yes |
| Use case | Values that change | Values that don't change | Legacy code only |
Rule of Thumb
Use const by default. Switch to let only when you need to reassign the variable. Never use var in modern JavaScript.
Use let when the value will change over time:
1let count = 0;2count = 1; // ✅ Reassignment is fine3count = count + 1; // ✅ count is now 245let temperature = 72;6temperature = 68; // ✅ Updated78// ❌ Cannot redeclare in the same scope9// let count = 5; // SyntaxError: Identifier 'count' has already been declared
Use const for values that should never be reassigned:
1const PI = 3.14159;2const API_URL = "https://api.example.com";3const MAX_RETRIES = 3;45// ❌ Cannot reassign6// PI = 3.14; // TypeError: Assignment to constant variable78// ⚠️ BUT: Objects and arrays declared with const CAN be modified9const user = { name: "Alice", age: 25 };10user.age = 26; // ✅ This works - we're modifying the object, not reassigning11console.log(user); // { name: "Alice", age: 26 }1213const colors = ["red", "green"];14colors.push("blue"); // ✅ Modifying the array is fine15console.log(colors); // ["red", "green", "blue"]
const Doesn't Mean Immutable
const prevents reassignment, not mutation. The variable binding is constant, but object/array contents can still change. To make an object truly immutable, use Object.freeze().
var was the only way to declare variables before ES6 (2015). It has two major quirks that cause bugs:
1// Problem 1: var is function-scoped, NOT block-scoped2if (true) {3var leaked = "I escaped the block!";4}5console.log(leaked); // "I escaped the block!" - 😱 shouldn't be accessible67// With let, this works correctly:8if (true) {9let contained = "I stay inside";10}11// console.log(contained); // ❌ ReferenceError1213// Problem 2: var is hoisted and initialized as undefined14console.log(ghost); // undefined (no error!)15var ghost = "boo";1617// With let, you get an error (safer):18// console.log(spirit); // ❌ ReferenceError: Cannot access 'spirit' before initialization19// let spirit = "boo";
Hoisting means variable declarations are moved to the top of their scope during compilation. But the behavior differs:
1// var is hoisted AND initialized as undefined2console.log(a); // undefined3var a = 10;45// let/const are hoisted but NOT initialized (Temporal Dead Zone)6// console.log(b); // ❌ ReferenceError7let b = 20;89// The Temporal Dead Zone (TDZ) is the period between10// entering the scope and the declaration being reached11{12// TDZ starts here for 'x'13// console.log(x); // ❌ ReferenceError14let x = 42; // TDZ ends here15console.log(x); // 42 ✅16}
JavaScript variable names must follow these rules:
1// ✅ Valid names2let firstName = "Alice"; // camelCase (recommended)3let _privateVar = true; // starts with underscore4let $element = "div"; // starts with dollar sign5let MAX_SIZE = 100; // UPPER_SNAKE_CASE for constants6let numberOfStudents = 42; // descriptive camelCase78// ❌ Invalid names9// let 1stPlace = "gold"; // cannot start with a number10// let my-name = "Alice"; // hyphens not allowed11// let class = "Math"; // 'class' is a reserved word
| Convention | Use For | Example |
|---|---|---|
camelCase | Variables, functions | userName, getTotal() |
PascalCase | Classes, components | UserProfile, Button |
UPPER_SNAKE_CASE | True constants | API_KEY, MAX_RETRIES |
_prefixed | "Private" values (convention) | _internalState |
1// Declare multiple variables2let x = 1, y = 2, z = 3;34// Destructuring (more on this in later topics)5const [a, b] = [10, 20];6console.log(a, b); // 10 2078const { name, age } = { name: "Bob", age: 30 };9console.log(name, age); // Bob 30
1const FREEZING_POINT_F = 32;2const CONVERSION_FACTOR = 5 / 9;34let celsius = 100;5let fahrenheit = (celsius * 9/5) + FREEZING_POINT_F;67console.log(celsius + "°C = " + fahrenheit + "°F");8// 100°C = 212°F910// Convert back11celsius = (fahrenheit - FREEZING_POINT_F) * CONVERSION_FACTOR;12console.log(fahrenheit + "°F = " + celsius + "°C");13// 212°F = 100°C
Notice how FREEZING_POINT_F and CONVERSION_FACTOR use const (they never change), while celsius and fahrenheit use let (they get reassigned).
Now that you can store values, let's explore the different data types JavaScript supports and how type coercion works behind the scenes.