Skip to content

ES6 - Variables

A variable is a named storage location in memory that holds a value. In JavaScript, variable names, or identifiers, must follow certain rules:

  • Cannot be reserved keywords (e.g., if, for, function).
  • Can contain letters, numbers, underscore (_), and dollar sign ($).
  • Must not start with a number.
  • Are case-sensitive (myVariable and MyVariable are different).

Before ES6, variables were declared using the var keyword. ES6 introduced let and const for more robust variable declaration and scoping.

Variables declared with var are either function-scoped or globally-scoped. They do not have block scope. var declarations are hoisted (see hoisting section).

var globalVar = "I'm global";
function exampleFunctionVar() {
var functionScopedVar = "I'm function-scoped";
console.log(functionScopedVar);
if (true) {
var blockVar = "I'm declared in a block, but still function-scoped with var";
console.log(blockVar);
}
console.log(blockVar); // Accessible here due to function scope
}
exampleFunctionVar();
// console.log(functionScopedVar); // Error: functionScopedVar is not defined globally

Variables declared with let are block-scoped. This means they are only accessible within the block (e.g., {...} in an if statement, for loop, or a standalone block) in which they are defined. let declarations are hoisted but not initialized, leading to a Temporal Dead Zone (TDZ).

let globalLet = "I'm global (using let)";
function exampleFunctionLet() {
let functionScopedLet = "I'm function-scoped (using let)";
console.log(functionScopedLet);
if (true) {
let blockScopedLet = "I'm truly block-scoped!";
console.log(blockScopedLet); // Accessible
}
// console.log(blockScopedLet); // Error: blockScopedLet is not defined here
}
exampleFunctionLet();

Variables declared with const are also block-scoped, like let. However, const declarations must be initialized at the time of declaration, and their value cannot be reassigned. This means the variable identifier cannot point to a new value.

Important: const does NOT make the value itself immutable. If a const variable holds an object or an array, the properties of the object or elements of the array can still be modified.

const PI = 3.14159;
// PI = 3.14; // Error: Assignment to constant variable.
const person = {
name: 'Alice',
age: 30
};
person.age = 31; // This is allowed! Modifying a property of the object.
console.log(person.age); // 31
// person = { name: 'Bob', age: 40 }; // Error: Cannot reassign the const variable 'person'.
const numbers = [1, 2, 3];
numbers.push(4); // Allowed
console.log(numbers); // [1, 2, 3, 4]
// numbers = [5, 6]; // Error

Initialization is the process of assigning an initial value to a variable. It can be done at the time of declaration or later (for var and let). const requires initialization at declaration.

let name; // Declaration
name = "Alice"; // Initialization
let city = "London"; // Declaration and initialization
const country = "UK"; // Declaration and initialization (must be done together for const)

JavaScript is a dynamically-typed language. This means you don’t have to specify the data type of a variable when you declare it, and the type of a variable can change during the execution of the program.

let myVar = 42; // myVar is a number
console.log(typeof myVar); // "number"
myVar = "Hello, world!"; // myVar is now a string
console.log(typeof myVar); // "string"
myVar = true; // myVar is now a boolean
console.log(typeof myVar); // "boolean"

Scope determines the accessibility (visibility) of variables. JavaScript has several types of scope:

  • Global Scope: Variables declared outside any function or block have global scope. They are accessible from anywhere in your JavaScript code. In browsers, global variables declared with var become properties of the window object. let and const declared globally do not.
  • Function Scope (Local Scope): Variables declared with var, let, or const inside a function are local to that function and cannot be accessed from outside.
  • Block Scope: Variables declared with let or const inside a block (e.g., within {} of an if, for, or just a standalone block) are only accessible within that block.
const globalNum = 10;
function checkScope() {
const functionNum = 100;
console.log('Inside function - globalNum:', globalNum); // 10
console.log('Inside function - functionNum:', functionNum); // 100
if (true) {
const blockNum = 200;
console.log('Inside block - globalNum:', globalNum); // 10
console.log('Inside block - functionNum:', functionNum); // 100
console.log('Inside block - blockNum:', blockNum); // 200
}
// console.log(blockNum); // Error: blockNum is not defined here (outside its block)
}
console.log('Outside function - globalNum:', globalNum); // 10
// console.log(functionNum); // Error: functionNum is not defined here (outside its function)
checkScope();

Shadowing: If you declare a variable within a certain scope (e.g., function or block) with the same name as a variable in an outer scope, the inner variable “shadows” the outer one within its scope.

Hoisting is JavaScript’s default behavior of moving declarations to the top of their respective scopes (global, function, or block) before code execution. However, only the declarations are hoisted, not initializations.

Declarations with var are hoisted to the top of their function or global scope, and they are initialized with undefined.

console.log(hoistedVar); // undefined (declaration hoisted, initialized to undefined)
var hoistedVar = "I am hoisted!";
console.log(hoistedVar); // "I am hoisted!"
// Internally, the above is treated somewhat like:
// var hoistedVar; // Declaration hoisted and initialized to undefined
// console.log(hoistedVar);
// hoistedVar = "I am hoisted!";
// console.log(hoistedVar);

let and const Hoisting (Temporal Dead Zone - TDZ):

Section titled “let and const Hoisting (Temporal Dead Zone - TDZ):”

Declarations with let and const are also hoisted to the top of their block scope, but they are not initialized. Accessing a let or const variable before its declaration (the line where it’s defined) results in a ReferenceError. The period from the start of the block until the declaration is encountered is called the Temporal Dead Zone (TDZ) for that variable.

// console.log(tdzLet); // ReferenceError: Cannot access 'tdzLet' before initialization (TDZ)
let tdzLet = "In TDZ until here";
console.log(tdzLet); // "In TDZ until here"
// console.log(tdzConst); // ReferenceError: Cannot access 'tdzConst' before initialization (TDZ)
const tdzConst = "Also in TDZ";
console.log(tdzConst); // "Also in TDZ"
  • Prefer const by default for variables whose values won’t be reassigned.
  • Use let for variables that need to be reassigned.
  • Avoid using var in modern JavaScript to prevent issues related to its function scoping and hoisting behavior.
  • Declare variables at the top of their scope (function or block) for better readability, even though hoisting happens automatically.