Skip to content

JavaScript Variables, Constants, and Declarations: The Foundation of Data Storage

In the world of programming, we need places to store various data—just like using sticky notes for to-do items, notebooks for ideas, and labels for items in real life. In JavaScript, variables and constants play these roles as containers for storing data.

What are Variables?

A variable is like a labeled box where you can put things and also change the contents of the box. The label is the variable name, and the content inside the box is the variable value.

javascript
// Creating a variable is like preparing a box
let userName = "Emily";

// You can look at what's inside the box
console.log(userName); // "Emily"

// You can change what's inside the box
userName = "David";
console.log(userName); // "David"

Three Declaration Methods: var, let, const

JavaScript provides three keywords for declaring variables. They are like three different types of containers, each with its own characteristics.

var—A Relic from the Past

var was JavaScript's earliest variable declaration method. Before ES6 (2015), it was the only choice. However, due to some issues, it's no longer recommended for use.

javascript
// Declare variables using var
var age = 25;
var city = "New York";
var isStudent = true;

console.log(age, city, isStudent); // 25 "New York" true

// var allows re-declaring variables with the same name (this is a problem!)
var age = 30; // No error, but easily causes confusion
console.log(age); // 30

Main problems with var:

  1. Function scope: Variables are only valid within functions, no block-level scope
  2. Variable hoisting: Declarations are moved to the top of the scope, potentially causing confusion
  3. Can be re-declared: Variables with the same name can be re-declared, easily causing errors
javascript
// Problem example 1: No block-level scope
if (true) {
  var message = "Hello";
}
console.log(message); // "Hello" - variable leaked outside!

for (var i = 0; i < 3; i++) {
  // Loop body
}
console.log(i); // 3 - loop variable leaked!

// Problem example 2: Variable hoisting
console.log(fruit); // undefined - no error, but results are confusing
var fruit = "apple";

// The above code is actually interpreted as:
var fruit;
console.log(fruit);
fruit = "apple";

let—Modern Variable Declaration

let is a new keyword introduced in ES6 that solves most of var's problems. It's like putting clear usage restrictions on boxes, making management more standardized.

javascript
// Declare variables using let
let userName = "Alice";
let userAge = 28;
let isActive = true;

// Variables declared with let can be modified
userName = "Bob";
userAge = 29;
isActive = false;

console.log(userName, userAge, isActive); // "Bob" 29 false

Advantages of let:

  1. Block scope: Variables are only valid within the code block where they are declared
  2. Cannot be re-declared: Variables with the same name cannot be declared in the same scope
  3. Temporal Dead Zone: Variables cannot be used before declaration
javascript
// Advantage 1: Block scope
if (true) {
  let message = "Hello";
  console.log(message); // "Hello"
}
console.log(message); // ReferenceError: message is not defined

for (let i = 0; i < 3; i++) {
  console.log(i); // 0, 1, 2
}
console.log(i); // ReferenceError: i is not defined

// Advantage 2: Cannot be re-declared
let score = 100;
let score = 200; // SyntaxError: Identifier 'score' has already been declared

// Advantage 3: Temporal Dead Zone (TDZ)
console.log(color); // ReferenceError: Cannot access 'color' before initialization
let color = "blue";

const—Guardian of Constants

const was also introduced in ES6 for declaring constants. It's like a box sealed with super glue—once you put something in, you can't change it anymore.

javascript
// Declare constants using const
const PI = 3.14159;
const API_URL = "https://api.example.com";
const MAX_USERS = 100;

// Trying to modify const variables will cause an error
PI = 3.14; // TypeError: Assignment to constant variable

console.log(PI); // 3.14159

Characteristics of const:

  1. Must be initialized: Must be assigned a value when declared
  2. Cannot be reassigned: Values cannot be changed
  3. Block scope: Same as let
  4. Object properties can be modified: If it's an object, object properties can still be modified
javascript
// Characteristic 1: Must be initialized
const name;  // SyntaxError: Missing initializer in const declaration
const name = "John";  // Correct

// Characteristic 2: Cannot be reassigned
const age = 25;
age = 26;  // TypeError: Assignment to constant variable

// Characteristic 4: Object properties can be modified (important!)
const user = {
  name: "Sarah",
  age: 25
};

// Cannot reassign the entire object
user = { name: "Tom", age: 30 };  // TypeError

// But can modify object properties
user.age = 26;
user.city = "London";
console.log(user);  // { name: "Sarah", age: 26, city: "London" }

// Same applies to arrays
const numbers = [1, 2, 3];
numbers.push(4);  // Can modify array contents
numbers[0] = 100;  // Can modify elements
console.log(numbers);  // [100, 2, 3, 4]

numbers = [5, 6, 7];  // TypeError: Assignment to constant variable

How to Use Object.freeze to Create True Constants

If you want to make an object completely immutable, you can use Object.freeze():

javascript
const config = Object.freeze({
  apiUrl: "https://api.example.com",
  timeout: 5000,
});

// Attempts to modify will silently fail (non-strict mode) or error (strict mode)
config.apiUrl = "https://new-api.example.com";
config.newProp = "value";

console.log(config);
// { apiUrl: "https://api.example.com", timeout: 5000 }
// No changes made

// In strict mode, it will error
("use strict");
const settings = Object.freeze({ theme: "dark" });
settings.theme = "light"; // TypeError: Cannot assign to read only property

Variable Naming Rules

Naming variables is like naming pets—you need to follow some rules and also some established best practices.

Must-Follow Rules

javascript
// 1. Can only contain letters, numbers, underscores (_), and dollar signs ($)
let userName = "valid";
let user_name = "valid";
let $user = "valid";
let _user = "valid";

// 2. Cannot start with a number
let 1user = "invalid";  // SyntaxError
let user1 = "valid";

// 3. Cannot use JavaScript reserved words
let let = "invalid";      // SyntaxError
let const = "invalid";    // SyntaxError
let function = "invalid"; // SyntaxError
let if = "invalid";       // SyntaxError

// 4. Case-sensitive
let name = "John";
let Name = "Sarah";
let NAME = "Michael";
// These are three different variables!

Best Practices

javascript
// 1. Use camelCase
let userName = "John";
let userAge = 25;
let isActive = true;
let getUserInfo = function () {};

// 2. Use uppercase + underscores for constants
const MAX_RETRY_COUNT = 3;
const API_BASE_URL = "https://api.example.com";
const DEFAULT_TIMEOUT = 5000;

// 3. Use meaningful names
// ❌ Bad naming
let x = "John";
let d = new Date();
let arr = [1, 2, 3];

// ✅ Good naming
let userName = "John";
let currentDate = new Date();
let userScores = [1, 2, 3];

// 4. Use is/has/can prefixes for boolean values
let isLoggedIn = true;
let hasPermission = false;
let canEdit = true;

// 5. For private variables, can use underscore prefix (convention)
let _privateVar = "private";
let _internalCounter = 0;

Understanding Scope

Scope determines the accessibility range of variables, just like different rooms in a house having different access permissions.

Global Scope

Variables declared outside any function or code block have global scope and can be accessed anywhere in the code.

javascript
// Global scope
let globalVar = "I am global";
const GLOBAL_CONST = 100;

function test() {
  console.log(globalVar); // Can access
  console.log(GLOBAL_CONST); // Can access
}

if (true) {
  console.log(globalVar); // Can access
}

test();

Function Scope

Variables declared inside a function can only be accessed within that function.

javascript
function myFunction() {
  let localVar = "I am local";

  console.log(localVar); // Can access
}

myFunction();
console.log(localVar); // ReferenceError: localVar is not defined

Block Scope

Variables declared with let and const have block scope, only valid within the code block (areas surrounded by {}) where they are declared.

javascript
if (true) {
  let blockVar = "I am in a block";
  const BLOCK_CONST = 200;

  console.log(blockVar); // Can access
  console.log(BLOCK_CONST); // Can access
}

console.log(blockVar); // ReferenceError
console.log(BLOCK_CONST); // ReferenceError

// Block scope in loops
for (let i = 0; i < 3; i++) {
  // i is a new variable each loop
  setTimeout(() => console.log(i), 100);
}
// Output: 0, 1, 2

// Compare with var behavior
for (var j = 0; j < 3; j++) {
  // All callbacks share the same j
  setTimeout(() => console.log(j), 100);
}
// Output: 3, 3, 3

Variable Hoisting

Variable hoisting is a JavaScript feature where variable and function declarations are moved to the top of their scope. Understanding this concept is important, although modern code rarely relies on it.

Hoisting of var

javascript
console.log(myVar); // undefined
var myVar = "Hello";

// The above code is actually executed as:
var myVar;
console.log(myVar);
myVar = "Hello";

Hoisting of let and const

let and const are also hoisted, but they are not initialized, causing a "Temporal Dead Zone."

javascript
console.log(myLet); // ReferenceError: Cannot access 'myLet' before initialization
let myLet = "Hello";

// Temporal Dead Zone (TDZ)
let x = 1;
{
  // In this block, x is not available before declaration
  console.log(x); // ReferenceError
  let x = 2; // This x is a new variable, shadowing the outer x
}

Which Declaration Method to Choose

This is an important decision in actual development. Here are the recommended selection strategies:

javascript
// 1. Use const by default
const userName = "Alex";
const userAge = 30;
const config = { theme: "dark" };

// 2. Only use let when variables need to be reassigned
let counter = 0;
counter++;
counter++;

let currentPage = 1;
currentPage = 2;

// 3. Avoid var (unless need to maintain compatibility with old code)
// Not recommended
var oldStyleVar = "avoid this";

// Practical example: loops
// ✅ Recommended
for (let i = 0; i < 10; i++) {
  console.log(i);
}

// ❌ Not recommended
for (var j = 0; j < 10; j++) {
  console.log(j);
}

// Practical example: configuration object
// ✅ Recommended
const appConfig = {
  name: "MyApp",
  version: "1.0.0",
};

// Can modify properties
appConfig.version = "1.0.1";

// But cannot reassign
// appConfig = {};  // TypeError

Declaring Without Assignment

Variables can be declared first and assigned values later.

javascript
// let can be declared and assigned later
let userName;
console.log(userName);  // undefined

userName = "Jessica";
console.log(userName);  // "Jessica"

// const must be assigned when declared
const userAge;  // SyntaxError: Missing initializer in const declaration

// Correct approach
const userAge = 25;

Multiple Variable Declarations

You can declare multiple variables in a single statement.

javascript
// Declare separately (recommended, clearer)
let firstName = "Tom";
let lastName = "Smith";
let age = 35;

// Declare together (compact but less readable)
let x = 1,
  y = 2,
  z = 3;

// Mixed declaration of different types
let name = "Laura",
  score = 95,
  isPassed = true,
  grade; // Can be uninitialized

// const can also do this
const PI = 3.14,
  E = 2.718,
  GOLDEN_RATIO = 1.618;

Common Problems and Solutions

Problem 1: Can const object properties be modified?

Answer: Properties can be modified, but the entire object cannot be reassigned.

javascript
const person = {
  name: "Anna",
  age: 28,
};

// ✅ Can modify properties
person.age = 29;
person.city = "Paris";

// ❌ Cannot reassign
person = { name: "Bob" }; // TypeError

// If you need a completely frozen object
const frozenPerson = Object.freeze({
  name: "Charlie",
  age: 40,
});

frozenPerson.age = 41; // Silently fails (non-strict mode)
console.log(frozenPerson.age); // Still 40

Problem 2: Why recommend let in loops?

Answer: let creates new bindings in each loop iteration, while var shares the same variable.

javascript
// Using let (correct)
for (let i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i); // Output 0, 1, 2
  }, 1000);
}

// Using var (problematic)
for (var j = 0; j < 3; j++) {
  setTimeout(() => {
    console.log(j); // Output 3, 3, 3
  }, 1000);
}

// Solution for var problem (using closures)
for (var k = 0; k < 3; k++) {
  (function (index) {
    setTimeout(() => {
      console.log(index); // Output 0, 1, 2
    }, 1000);
  })(k);
}

Problem 3: What happens with undeclared variables?

Answer: Direct use of undeclared variables creates global variables (non-strict mode) or causes errors (strict mode).

javascript
// Non-strict mode
function test() {
  undeclaredVar = "Oops!"; // Accidentally creates global variable
}

test();
console.log(undeclaredVar); // "Oops!" - global pollution!

// Strict mode (recommended)
("use strict");
function strictTest() {
  undeclaredVar = "Error!"; // ReferenceError: undeclaredVar is not defined
}

Summary

Variables and constants are the foundation of JavaScript programming. Choosing the right declaration method makes code safer and more maintainable.

Key Points Review:

  • var: Function scope, has variable hoisting, not recommended for use
  • let: Block scope, can be reassigned, preferred choice in modern development
  • const: Block scope, cannot be reassigned, used for constants and immutable references
  • Best practices: Use const by default, use let when changes are needed, avoid var
  • Naming rules: Use meaningful names, follow camelCase
  • Scope: Understand differences between global, function, and block-level scopes
  • Properties of const-declared objects can be modified, but the object reference cannot be changed