Variables and Memory
Programs compute by transforming values. Variables give names to intermediate results so we can refer to them, combine them, and build larger computations from smaller ones.
The Essence of Variables
A variable binds a name to a value. This is not merely convenient—it's the foundation of abstraction in programming:
// Without variables: unreadable, unchangeable
console.log(100 * 0.08 + 100); // What is this computing?
// With variables: intention is clear
const price = 100;
const taxRate = 0.08;
const total = price * taxRate + price;
console.log(total); // 108The second version isn't just easier to read. It's easier to change. Need a different tax rate? Change one number. Need to compute something else with price? It's already named.
This is the first principle: name things to make them reusable and changeable.
// Creating a variable
let age = 25;
// Using it
console.log(age); // 25The let keyword declares a new variable. The = operator binds the name age to the value 25.
Expressions and Values
Before we go further, understand the difference between expressions and statements:
- An expression produces a value:
2 + 3,"hello".toUpperCase(),x * y - A statement performs an action:
let x = 5;,console.log(x);
Every expression can be stored in a variable. This is how we build complex computations from simple parts.
Types of Values
JavaScript has a small set of fundamental types. Understanding these precisely prevents bugs:
Numbers
All numbers in JavaScript are 64-bit floating-point. There is no separate integer type:
const count = 42; // Looks like an integer
const price = 19.99; // Decimal
const temperature = -5; // Negative
// But watch out - floating point has precision limits
console.log(0.1 + 0.2); // 0.30000000000000004, not 0.3!Arithmetic operators work as expected:
const sum = 10 + 5; // Addition: 15
const difference = 20 - 8; // Subtraction: 12
const product = 6 * 7; // Multiplication: 42
const quotient = 15 / 3; // Division: 5
const remainder = 10 % 3; // Modulo (remainder): 1Strings
Strings are sequences of characters:
const name = "Alice";
const greeting = 'Hello';
const message = `Hello, ${name}!`; // Template literalTemplate literals (backticks) embed expressions directly: ${expression} evaluates the expression and converts it to a string.
Booleans
Booleans are truth values—true or false. They are the foundation of all conditional logic:
const isLoggedIn = true;
const hasPermission = false;Undefined and Null
Two kinds of "nothing":
let notSet; // undefined - never assigned
const emptyValue = null; // null - explicitly "no value"Use null to explicitly indicate "no value." Undefined usually means "forgot to initialize."
Type Coercion: The JavaScript Trap
JavaScript automatically converts types. This causes bugs that haunt production code for years:
// String + Number = String (concatenation)
console.log("5" + 3); // "53" (not 8!)
// String - Number = Number (arithmetic)
console.log("5" - 3); // 2
// Comparison madness
console.log("10" > "9"); // false! (string comparison: "1" < "9")
console.log("10" > 9); // true (number comparison)Primitives vs References: A Mental Model of Memory
This section will shape how you think about data for your entire programming career.
The Stack and the Heap
When your program runs, it uses two regions of memory:
- Stack: Fast, organized. Stores primitive values and references. Fixed size per value.
- Heap: Flexible, larger. Stores objects and arrays. Variable size.
Primitive Values Live on the Stack
Numbers, strings, booleans, null, and undefined are primitives. They're stored directly where the variable is:
let x = 10;
let y = x; // y gets a COPY of the value 10
x = 20; // Changing x does NOT affect y
console.log(y); // Still 10Picture it:
Each variable holds its own copy. They are independent.
Reference Values Point to the Heap
Arrays and objects are reference types. The variable holds a reference (an address) that points to data stored elsewhere:
const arr1 = [1, 2, 3];
const arr2 = arr1; // arr2 gets a COPY of the REFERENCE
arr1.push(4);
console.log(arr2); // [1, 2, 3, 4] - same array!Picture it:
Both variables point to the same array. When you modify through one, you see the change through the other.
Why This Matters
This distinction explains:
- Why
const arr = [1,2,3]; arr.push(4);works (you're not reassigningarr, just modifying what it points to) - Why passing objects to functions can modify the original
- Why you need to explicitly copy arrays/objects if you want independence
Declaring Variables: The Philosophy of Mutability
JavaScript provides three keywords for declaring variables:
let message = "Hello"; // Can be reassigned
const PI = 3.14159; // Cannot be reassigned
var oldStyle = "avoid"; // Legacy; has confusing scoping rulesThe Case for Immutability
Prefer const by default. This is not a style preference—it's a fundamental principle of reliable software:
// Good: const by default
const userName = "Alice";
const taxRate = 0.08;
const items = [1, 2, 3]; // The reference is const, not the contents
// Good: let only when mutation is necessary
let counter = 0;
counter = counter + 1;Why does immutability matter?
-
Easier to reason about: If
taxRateisconst, you know it's 0.08 everywhere. No need to trace where it might have changed. -
Fewer bugs: Most bugs involve unexpected state changes. Fewer mutable variables = fewer places for bugs to hide.
-
Better for concurrency: Immutable data can be safely shared across threads (relevant in workers and future JavaScript features).
-
Self-documenting:
constsays "this is a fact."letsays "this accumulates or tracks something that changes."
// let signals intent: "this changes over time"
let totalSales = 0;
for (const sale of sales) {
totalSales += sale.amount;
}
// const signals intent: "this is computed once and done"
const average = totalSales / sales.length;When to Use let
Use let for:
- Loop counters
- Accumulators (totals, sums)
- Values that legitimately change over time (current user, selected item)
If you find yourself writing let frequently, ask whether your approach could use more pure functions and transformations instead of mutations.
Naming Variables
Names are not for the computer. The computer doesn't care if you call a variable x or totalRevenueFromQuarterlySubscriptions. Names are for humans—including future you.
The Rules
- Must start with a letter, underscore, or dollar sign
- Can contain letters, numbers, underscores, dollar signs
- Cannot be reserved words (
let,if,class, etc.)
The Art
Good names reveal intent without requiring comments:
// Good: reveals what it IS and why it exists
const userName = "Alice";
const itemCount = 10;
const isValidInput = true;
const MAX_LOGIN_ATTEMPTS = 3; // Constants in UPPER_SNAKE_CASE
// Bad: requires you to read surrounding code to understand
const x = "Alice";
const n = 10;
const flag = true;Conventions:
- camelCase for variables and functions:
firstName,calculateTotal - UPPER_SNAKE_CASE for true constants:
MAX_RETRIES,API_BASE_URL - PascalCase for classes and components:
UserAccount,ShoppingCart
Boolean Naming
Booleans should read like yes/no questions:
// Good: reads like a question
const isLoading = true;
const hasPermission = false;
const canEdit = user.role === "admin";
// Bad: unclear what true/false means
const loading = true;
const permission = false;
const edit = true;Using Variables: Building Computation
Variables let you compose complex calculations from simple parts:
const price = 19.99;
const quantity = 3;
const subtotal = price * quantity;
const tax = subtotal * 0.08;
const total = subtotal + tax;
console.log(total); // 64.77Compare to the "clever" one-liner:
console.log(19.99 * 3 * 1.08); // What is this computing?The first version is longer but:
- Each step is named and understandable
- Intermediate values can be inspected for debugging
- Changes require modifying one place, not re-deriving the formula
- The code explains itself
Reassignment
With let, you can reassign:
let score = 100;
score = score + 10; // Now 110
score += 10; // Shorthand: now 120The +=, -=, *=, /= operators combine arithmetic and assignment.
The Scope of a Variable
A variable exists only within the block where it's declared:
const x = 1;
if (true) {
const y = 2; // y exists only inside this block
console.log(x); // 1 - can access outer variable
console.log(y); // 2
}
console.log(x); // 1
console.log(y); // ERROR: y is not definedThis is called block scoping. It prevents variables from leaking into places they don't belong.
Check Your Understanding
Which keyword creates a variable that cannot be reassigned?
What happens when you assign an array to another variable?
What does '5' + 3 evaluate to in JavaScript?
Why should you prefer const over let?
Try It Yourself
Practice creating and using variables:
Key Principles
1. Variables name intermediate results. Naming makes code readable, debuggable, and changeable.
2. Know your types. JavaScript has primitives (number, string, boolean, null, undefined) and reference types (objects, arrays). They behave differently on assignment.
3. Primitives copy by value; references copy by reference. Two variables can point to the same object. Understand this or suffer mysterious bugs.
4. Prefer immutability. Use const by default. Mutable state is where bugs hide.
5. Type coercion is a trap. Always use ===, know what types you're working with, convert explicitly when needed.
6. Names are documentation. Future readers (including you) will thank you for isValidInput instead of flag.
Summary
You learned:
- Variables bind names to values, enabling abstraction and reuse
- Expressions produce values; statements perform actions
- JavaScript's six primitive types and their behaviors
- The stack/heap mental model for primitives vs references
- Why immutability (
const) leads to more reliable code - Type coercion dangers and how to avoid them
- Scope: variables exist only within their declaring block
These concepts transfer to every programming language you'll ever learn. The syntax changes; the principles don't.
Next, we explore how to control which parts of your code run and how to repeat actions using control flow.