JS Variables Guide: How to Declare and Use Them
Learn how to declare, initialize, and use JavaScript variables with let, const, and var. This guide covers variable types, assignment, reassignment, and practical patterns every beginner needs to know.
Variables are the foundation of every JavaScript program. They are named containers that store values so you can reference, update, and manipulate data throughout your code. Without variables, every calculation would be lost the moment it was computed, and you would have no way to track user input, API responses, or application state.
Think of a variable like a labeled box in a warehouse. The label is the variable name (userName, totalPrice, isLoggedIn), and the contents are the value ("Alice", 49.99, true). You can look inside the box to read the value, swap the contents for a new value, or move the box around your program. JavaScript gives you three keywords for creating these boxes: let, const, and var.
This guide covers everything a beginner needs to know about JavaScript variables: how to declare them, what values they hold, when to use each keyword, and the common mistakes that trip up new developers.
Declaring Variables: The Three Keywords
JavaScript provides three ways to declare a variable. Each has different behavior for reassignment, scope, and hoisting.
// Using let: can be reassigned, block-scoped
let currentScore = 0;
currentScore = 10; // Allowed: let variables can be reassigned
// Using const: cannot be reassigned, block-scoped
const MAX_RETRIES = 3;
// MAX_RETRIES = 5; // Error: Assignment to constant variable
// Using var: can be reassigned, function-scoped (legacy)
var playerName = "Alice";
playerName = "Bob"; // Allowed: var variables can be reassigned| Keyword | Reassignable | Scope | Hoisted | Introduced |
|---|---|---|---|---|
let | Yes | Block ({}) | Yes (but not initialized) | ES6 (2015) |
const | No | Block ({}) | Yes (but not initialized) | ES6 (2015) |
var | Yes | Function | Yes (initialized as undefined) | ES1 (1997) |
Which Keyword Should You Default To?
Use const for every variable unless you know the value needs to change. If it does need to change, use let. Avoid var in modern JavaScript. This pattern makes your code easier to reason about because most values in a well-written program do not need reassignment.
Declaration vs. Initialization
There is an important distinction between declaring a variable (creating the name) and initializing it (assigning the first value).
// Declaration only (no value assigned yet)
let temperature;
console.log(temperature); // undefined (declared but not initialized)
// Initialization (assigning the first value)
temperature = 22.5;
console.log(temperature); // 22.5
// Declaration + initialization in one step (recommended)
let humidity = 65;
console.log(humidity); // 65
// const MUST be initialized at declaration
const API_URL = "https://api.example.com";
// const API_KEY; // SyntaxError: Missing initializer in const declarationMultiple Declarations on One Line
You can declare multiple variables in a single statement, but this can hurt readability:
// Multiple declarations (technically valid but harder to read)
let x = 1, y = 2, z = 3;
// Preferred: one declaration per line for clarity
let width = 800;
let height = 600;
let depth = 100;What Values Can Variables Hold?
JavaScript variables can hold any of the language's data types. These fall into two categories: primitive types and reference types.
Primitive Types
Primitives are simple, immutable values stored directly in the variable.
// String: text data
const firstName = "Sarah";
const greeting = `Hello, ${firstName}!`; // Template literal
// Number: integers and decimals (no separate int/float types)
const age = 28;
const price = 49.99;
const negative = -15;
// Boolean: true or false
const isActive = true;
const hasPermission = false;
// Undefined: variable declared but not assigned
let middleName;
console.log(middleName); // undefined
// Null: intentionally empty value
const selectedItem = null;
// BigInt: very large integers (append n)
const largeNumber = 9007199254740991n;
// Symbol: unique identifier (advanced use)
const id = Symbol("user-id");Reference Types
Reference types store a reference (memory address) to the actual data, which lives in a different area of memory called the heap.
// Object: collection of key-value pairs
const user = {
name: "Sarah",
age: 28,
role: "developer"
};
// Array: ordered list of values
const scores = [95, 87, 92, 78, 88];
// Function: reusable block of code
const calculateAverage = (numbers) => {
const sum = numbers.reduce((total, n) => total + n, 0);
return sum / numbers.length;
};
console.log(calculateAverage(scores)); // 88| Type Category | Types | Stored As | Copy Behavior |
|---|---|---|---|
| Primitive | String, Number, Boolean, Undefined, Null, BigInt, Symbol | Value itself | Creates independent copy |
| Reference | Object, Array, Function, Date, RegExp, Map, Set | Memory address | Copies the reference (both point to same data) |
const Does Not Mean Immutable for Objects
Declaring an object or array with const prevents you from reassigning the variable to a completely new object, but you can still modify the properties or elements inside it. The reference is constant, not the contents.
const config = { theme: "dark", fontSize: 16 };
// This is allowed: modifying a property
config.theme = "light";
config.language = "en";
console.log(config); // { theme: "light", fontSize: 16, language: "en" }
// This is NOT allowed: reassigning the variable
// config = { theme: "blue" }; // TypeError: Assignment to constant variableVariable Scope: Where Variables Are Accessible
Scope determines where in your code a variable can be accessed. Understanding scope prevents bugs caused by variables leaking into areas where they should not exist.
Block Scope (let and const)
Variables declared with let and const exist only inside the curly braces {} where they are declared.
const temperature = 35;
if (temperature > 30) {
const message = "It's hot outside!";
let warningLevel = "high";
console.log(message); // "It's hot outside!"
console.log(warningLevel); // "high"
}
// console.log(message); // ReferenceError: message is not defined
// console.log(warningLevel); // ReferenceError: warningLevel is not defined
// Both variables are inaccessible outside the if blockFunction Scope (var)
Variables declared with var are accessible anywhere inside the function where they are declared, regardless of block boundaries.
function processOrder(items) {
if (items.length > 0) {
var discount = 0.1; // var ignores block scope
}
// discount is accessible here because var is function-scoped
console.log(discount); // 0.1
}
processOrder(["laptop", "mouse"]);Global Scope
Variables declared outside any function or block are global and accessible everywhere.
// Global variables (accessible everywhere)
const APP_NAME = "RuneHub";
let visitorCount = 0;
function incrementVisitor() {
visitorCount += 1; // Can access global variable
console.log(`${APP_NAME} visitor #${visitorCount}`);
}
incrementVisitor(); // "RuneHub visitor #1"
incrementVisitor(); // "RuneHub visitor #2"Reassignment and Mutation
Understanding the difference between reassignment (changing what the variable points to) and mutation (changing the contents of what it points to) is essential.
// REASSIGNMENT: changing the variable's value entirely
let count = 5;
count = 10; // Reassignment: count now holds 10
// const prevents reassignment
const limit = 100;
// limit = 200; // TypeError: Assignment to constant variable
// MUTATION: changing the internals of a reference type
const cart = ["apple", "banana"];
cart.push("cherry"); // Mutation: modifying the array's contents
console.log(cart); // ["apple", "banana", "cherry"]
// This works because we did not reassign cart,
// we changed the contents of the array it references
// Reassignment vs mutation with objects
const settings = { volume: 50 };
settings.volume = 80; // Mutation: OK with const
// settings = { volume: 80 }; // Reassignment: Error with constPractical Patterns for Using Variables
Pattern 1: Accumulator
// Building up a result step by step
const items = [
{ name: "Notebook", price: 12.99 },
{ name: "Pen Set", price: 8.49 },
{ name: "Backpack", price: 45.00 },
{ name: "Calculator", price: 24.99 }
];
let totalCost = 0; // Accumulator: will be reassigned, so use let
for (const item of items) {
totalCost += item.price;
}
const TAX_RATE = 0.08; // Constant: will not change
const tax = totalCost * TAX_RATE;
const finalTotal = totalCost + tax;
console.log(`Subtotal: $${totalCost.toFixed(2)}`); // $91.47
console.log(`Tax: $${tax.toFixed(2)}`); // $7.32
console.log(`Total: $${finalTotal.toFixed(2)}`); // $98.79Pattern 2: Configuration Object
// Use const for configuration objects: the reference stays constant
const appConfig = {
apiBaseUrl: "https://api.example.com",
maxRetries: 3,
timeoutMs: 5000,
features: {
darkMode: true,
notifications: true,
analytics: false
}
};
// Access and use configuration values
function fetchData(endpoint) {
const url = `${appConfig.apiBaseUrl}${endpoint}`;
const timeout = appConfig.timeoutMs;
console.log(`Fetching ${url} with ${timeout}ms timeout`);
}
fetchData("/users"); // "Fetching https://api.example.com/users with 5000ms timeout"Pattern 3: Conditional Assignment
// Assign different values based on conditions
const hour = new Date().getHours();
let period;
if (hour < 12) {
period = "morning";
} else if (hour < 17) {
period = "afternoon";
} else {
period = "evening";
}
// Shorter version with ternary operator
const isMorning = hour < 12 ? "Yes" : "No";
// Default values with nullish coalescing
const userTheme = null;
const activeTheme = userTheme ?? "system"; // "system" (because userTheme is null)
console.log(`Good ${period}! Theme: ${activeTheme}`);Best Practices
Default to const for every variable. Only switch to let when you genuinely need to reassign the value. This makes your code easier to read because anyone scanning it knows that const values will not change.
Use descriptive, meaningful names. A variable named userSubscriptionStatus tells you exactly what it holds. A variable named x or temp forces everyone (including your future self) to trace through the code to understand its purpose.
Declare variables close to where they are used. Placing a variable declaration 50 lines before its first use makes the code harder to follow. Declare each variable as close as possible to the code that reads or modifies it.
Initialize variables at declaration. Declaring a variable without a value (let total;) creates an undefined value that can cause subtle bugs. Whenever possible, assign a meaningful initial value at declaration time.
Use UPPER_SNAKE_CASE for true constants. Values that are known at write time and never change (API URLs, configuration limits, mathematical constants) should use UPPER_SNAKE_CASE to signal their intent: const MAX_FILE_SIZE = 5242880;.
Common Mistakes and How to Avoid Them
Variable Declaration Pitfalls
These mistakes cause real bugs in beginner and intermediate codebases.
Declaring variables without a keyword. In non-strict mode, count = 5; (without let, const, or var) creates an accidental global variable. Always use a keyword. Enable strict mode ("use strict";) to catch this as an error.
Using const when you need to reassign. If a value changes inside a loop or conditional, declare it with let. Trying to reassign a const variable throws a TypeError at runtime.
Assuming const makes objects immutable. const prevents reassignment, not mutation. If you need a truly immutable object, use Object.freeze(), though it only applies to the top level (shallow freeze).
Shadowing variables unintentionally. Declaring a new variable with the same name in an inner scope "shadows" the outer variable, making the outer one inaccessible inside that block. This can cause bugs that are hard to trace.
const name = "Alice";
function greet() {
const name = "Bob"; // Shadows the outer 'name'
console.log(name); // "Bob" (not "Alice")
}
greet();
console.log(name); // "Alice" (outer variable unaffected)Next Steps
Learn [variable naming](/tutorials/programming-languages/javascript/javascript-variable-naming-conventions-rules) conventions
Explore JavaScript variable naming conventions and rules to write code that is consistent, readable, and follows industry standards.
Understand variable scope in depth
Dive deeper into global vs local variables to understand how scope affects variable accessibility across functions and blocks.
Compare var, let, and const
Read the detailed comparison of var vs let vs const to understand hoisting, the temporal dead zone, and why modern JavaScript prefers let and const.
Learn JavaScript data types
Variables store data, so understanding JavaScript's type system (strings, numbers, booleans, objects, arrays) is the natural next step in your learning journey.
Rune AI
Key Insights
- Default to const: Use
constfor every variable and switch toletonly when you need reassignment; avoidvarentirely - Scope matters:
letandconstare block-scoped (limited to{}), whilevaris function-scoped (leaks out of blocks) - const prevents reassignment, not mutation: Objects and arrays declared with
constcan have their contents modified; only the variable binding is locked - Initialize at declaration: Always assign a value when you declare a variable to avoid
undefinedbugs - Descriptive names: Clear, meaningful variable names make your code self-documenting and reduce the need for comments
Frequently Asked Questions
What is the difference between let and const?
Can I use var in modern JavaScript?
Why does const allow modifying object properties?
What happens if I declare a variable without let, const, or var?
How many variables should I declare per line?
Conclusion
JavaScript variables are the building blocks of every program you will write. Choosing between const and let communicates intent to anyone reading your code: const signals a value that will not be reassigned, while let signals a value that changes over its lifetime. Understanding declaration, initialization, scope, and the difference between reassignment and mutation gives you a solid foundation for writing clear, bug-free JavaScript.
More in this topic
OffscreenCanvas API in JS for UI Performance
Master the OffscreenCanvas API to offload rendering from the main thread. Covers worker-based 2D and WebGL rendering, animation loops inside workers, bitmap transfer, double buffering, chart rendering pipelines, image processing, and performance measurement strategies.
Advanced Web Workers for High Performance JS
Master Web Workers for truly parallel JavaScript execution. Covers dedicated and shared workers, structured cloning, transferable objects, SharedArrayBuffer with Atomics, worker pools, task scheduling, Comlink RPC patterns, module workers, and performance profiling strategies.
JavaScript Macros and Abstract Code Generation
Master JavaScript code generation techniques for compile-time and runtime metaprogramming. Covers AST manipulation, Babel plugin authorship, tagged template literals as macros, code generation pipelines, source-to-source transformation, compile-time evaluation, and safe eval alternatives.