JavaScript Basics Chapter 1: The Tale of Three Siblings - var, let, and const
Welcome to JavaScript Land: Chapter 1
This is Chapter 1 of our JavaScript adventure. If you’re just joining us, start with the Table of Contents to see the full journey ahead.
Chapter 1: The Tale of Three Siblings - var, let, and const
In the kingdom of JavaScript, there lived three siblings who handled variable declarations. Each had their own personality and rules about how they behaved in different situations.
The Eldest Sibling: var (The Rebellious One)
var was the oldest and most unpredictable. Born in the early days of JavaScript, var had some quirky habits:
// var's weird hoisting behavior
console.log("Hey there, " + name); // "Hey there, undefined"
var name = "JavaScript";
// What actually happens behind the scenes:
var name; // hoisted and initialized with undefined
console.log("Hey there, " + name);
name = "JavaScript";
var’s characteristics:
- Function scoped or globally scoped (ignores block boundaries like
{}) - Hoisted and initialized with
undefined - Can be re-declared and updated without complaints
- Prone to creating bugs due to its loose nature
// var ignores block scope - dangerous!
if (true) {
var secret = "I escape blocks!";
}
console.log(secret); // "I escape blocks!" - var leaked out!
// Function scope works though
function keepSecret() {
var actualSecret = "I'm safe here";
}
// console.log(actualSecret); // ReferenceError - can't escape functions
The Middle Child: let (The Responsible One)
let came along in ES6 as the responsible middle child, learning from var’s mistakes:
// let's proper behavior
console.log(age); // ReferenceError: Cannot access 'age' before initialization
let age = 25;
let’s characteristics:
- Block scoped (respects
{}boundaries) - Hoisted but NOT initialized - lives in the “Temporal Dead Zone” until declaration
- Cannot be re-declared in same scope but can be updated
- Much safer than var
// let respects block scope
if (true) {
let secret = "I stay in my block";
}
// console.log(secret); // ReferenceError - secret is contained
// let prevents accidental re-declaration
let name = "Alice";
// let name = "Bob"; // SyntaxError - can't re-declare
// But updating is fine
name = "Bob"; // This works
The Youngest: const (The Unchanging One)
const is the strictest sibling, representing constants and immutable bindings:
// const must be initialized
// const PI; // SyntaxError - missing initializer
const PI = 3.14159;
// PI = 3.14; // TypeError - can't reassign
// But objects and arrays are tricky...
const person = { name: "Alice" };
person.name = "Bob"; // This works! We're not changing the reference
person.age = 30; // This works too!
const numbers = [1, 2, 3];
numbers.push(4); // This works! Array methods can modify contents
// numbers = [5, 6, 7]; // TypeError - can't reassign the reference
const’s characteristics:
- Block scoped like let
- Hoisted but NOT initialized (Temporal Dead Zone)
- Cannot be re-declared or reassigned
- For objects/arrays, the reference is constant but contents can mutate
The Temporal Dead Zone: A Mysterious Place
The Temporal Dead Zone (TDZ) is like a limbo where let and const variables exist but cannot be accessed:
console.log(typeof myVar); // "undefined" - var is forgiving
console.log(typeof myLet); // ReferenceError - TDZ strikes!
var myVar = "I'm hoisted and initialized";
let myLet = "I'm hoisted but in TDZ until now";
What’s Next?
Our three variable siblings have set the stage for our JavaScript adventure. In the next chapter, we’ll explore the Data Type Kingdom and meet all the different types of values that can live in our variables.
Continue the journey:
- Next: Chapter 2: The Data Type Kingdom
- Table of Contents: JavaScript Guide - Table of Contents
“In the beginning, there was var, and var was with scope confusion. Then came let and const, bringing order to the chaos of variable declarations.”