What Are Variables?

A variable is a named container that holds a value. Think of it as a labeled box where you store data that your program needs to remember. In JavaScript, you create variables using special keywords: let, const, or var.

let name = "Alice";
const age = 25;
var city = "London";

console.log(name);  // "Alice"
console.log(age);   // 25
console.log(city);  // "London"

Unlike Python where you simply write name = "Alice", JavaScript requires a declaration keyword. This tells the engine how the variable should behave — whether it can be reassigned, and what scope it lives in.

Variable Naming Rules

  • Must start with a letter, underscore (_), or dollar sign ($)
  • Can contain letters, numbers, underscores, and dollar signs
  • Are case-sensitive (Name and name are different)
  • Cannot be reserved words (let, class, return, etc.)
  • Convention: use camelCase for variables and functions (userName, totalPrice)
// Good variable names
let userName = "Alice";
let totalPrice = 49.99;
let isLoggedIn = true;
let _privateVar = "internal";
let $element = "DOM node";

// Bad variable names (will cause errors)
// let 2fast = "no";       // can't start with a number
// let my-name = "no";     // hyphens not allowed
// let let = "no";         // reserved word

let vs const vs var

let — Reassignable Block-Scoped Variable

Use let when the value will change. It is block-scoped, meaning it only exists inside the nearest { } block.

let score = 0;
score = 10;        // allowed — reassignment is fine
score = score + 5; // score is now 15

let message = "hello";
message = "goodbye"; // allowed

const — Constant Block-Scoped Variable

Use const when the value should never be reassigned. It must be initialized when declared.

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

// PI = 3.14;  // TypeError: Assignment to constant variable
💡
Prefer const by default

Use const for every variable unless you know it needs to be reassigned. This makes your code easier to reason about — when you see const, you know the binding will never change. Only switch to let when reassignment is actually needed. Note that const prevents reassignment of the variable, but objects and arrays declared with const can still have their contents modified.

// const prevents reassignment, not mutation
const colors = ["red", "green", "blue"];
colors.push("yellow");     // allowed — modifying the array
// colors = ["new array"]; // TypeError — reassigning the variable

const user = { name: "Alice" };
user.name = "Bob";         // allowed — modifying a property
// user = { name: "Bob" }; // TypeError — reassigning the variable

var — The Legacy Keyword

var is the original way to declare variables in JavaScript. It is function-scoped (not block-scoped), which leads to confusing behavior. Modern code should use let and const instead.

// var is function-scoped, not block-scoped
if (true) {
    var leaked = "I'm visible outside!";
    let contained = "I stay inside";
}
console.log(leaked);     // "I'm visible outside!" — var leaks out
// console.log(contained); // ReferenceError — let stays in the block

// var allows redeclaration (confusing!)
var name = "Alice";
var name = "Bob";   // no error — silently overwrites
console.log(name);  // "Bob"

// let does not allow redeclaration
let age = 25;
// let age = 30;    // SyntaxError: already declared

Data Types

JavaScript has seven primitive data types and one complex type (Object). Here are the primitives you will use most often:

String

Strings represent text. They can be wrapped in single quotes, double quotes, or backticks:

const single = 'Hello';
const double = "World";
const backtick = `Hello, ${double}`; // template literal

// String properties and methods
const greeting = "Hello, World!";
console.log(greeting.length);          // 13
console.log(greeting.toUpperCase());   // "HELLO, WORLD!"
console.log(greeting.toLowerCase());   // "hello, world!"
console.log(greeting.includes("World")); // true
console.log(greeting.indexOf("World"));  // 7
console.log(greeting.slice(0, 5));       // "Hello"
console.log(greeting.replace("World", "JavaScript")); // "Hello, JavaScript!"
console.log(greeting.split(", "));       // ["Hello", "World!"]

Number

JavaScript has a single number type for both integers and decimals (unlike Python which separates int and float):

const integer = 42;
const decimal = 3.14;
const negative = -10;
const big = 1_000_000;  // underscores for readability (same as 1000000)

// Arithmetic operations
console.log(10 + 3);    // 13
console.log(10 - 3);    // 7
console.log(10 * 3);    // 30
console.log(10 / 3);    // 3.3333333333333335
console.log(10 % 3);    // 1 (remainder)
console.log(10 ** 3);   // 1000 (exponentiation)

// Special number values
console.log(Infinity);          // Infinity
console.log(-Infinity);         // -Infinity
console.log(0 / 0);            // NaN (Not a Number)
console.log(isNaN("hello"));   // true
console.log(Number.isFinite(42)); // true

Boolean

Booleans represent true or false (lowercase in JavaScript, unlike Python's True/False):

const isLoggedIn = true;
const isAdmin = false;

// Comparison operators return booleans
console.log(5 > 3);     // true
console.log(10 === 10);  // true
console.log(5 !== 3);    // true
console.log(5 >= 5);    // true
console.log(3 < 1);     // false

// Logical operators
console.log(true && false);  // false (AND — both must be true)
console.log(true || false);  // true  (OR — at least one true)
console.log(!true);          // false (NOT — inverts the value)

null and undefined

These two types represent "absence of value," but they differ in intent:

// undefined — variable declared but not assigned
let x;
console.log(x);        // undefined

// null — intentionally set to "no value"
let user = null;       // explicitly means "no user yet"
console.log(user);     // null

// The difference:
// undefined = "hasn't been given a value yet"
// null = "deliberately set to empty"

console.log(typeof undefined); // "undefined"
console.log(typeof null);      // "object" (this is a known JavaScript quirk)

Symbol

Symbols are unique identifiers. They are an advanced feature used primarily for object property keys that should never collide:

const id1 = Symbol("id");
const id2 = Symbol("id");

console.log(id1 === id2);  // false — every Symbol is unique
console.log(typeof id1);   // "symbol"

Type Checking with typeof

Use the typeof operator to check what type a value is. It returns a string:

console.log(typeof "hello");     // "string"
console.log(typeof 42);          // "number"
console.log(typeof 3.14);        // "number" (no separate float type)
console.log(typeof true);        // "boolean"
console.log(typeof undefined);   // "undefined"
console.log(typeof null);        // "object" (historical bug, never fixed)
console.log(typeof Symbol("x")); // "symbol"
console.log(typeof {});          // "object"
console.log(typeof []);          // "object" (arrays are objects!)
console.log(typeof function(){}); // "function"

// To check for arrays specifically:
console.log(Array.isArray([1, 2, 3]));  // true
console.log(Array.isArray("hello"));    // false

Type Coercion and Comparison

JavaScript automatically converts types in certain situations. This is called type coercion, and it is one of the trickiest parts of the language.

Implicit Coercion

// String concatenation wins over addition
console.log("5" + 3);       // "53" (number coerced to string)
console.log("5" + true);    // "5true"

// Other operators convert to numbers
console.log("5" - 3);       // 2 (string coerced to number)
console.log("5" * 2);       // 10
console.log("5" / 1);       // 5
console.log(true + 1);      // 2 (true becomes 1)
console.log(false + 1);     // 1 (false becomes 0)

// Truthy and falsy values
// These are "falsy" (evaluate to false in boolean context):
// false, 0, -0, "", null, undefined, NaN
// Everything else is "truthy"

console.log(Boolean(0));          // false
console.log(Boolean(""));         // false
console.log(Boolean(null));       // false
console.log(Boolean("hello"));    // true
console.log(Boolean(42));         // true
console.log(Boolean([]));         // true (empty array is truthy!)

== vs === (Loose vs Strict Equality)

⚠️
Always use === and !== (strict equality)

The loose equality operator == performs type coercion before comparing, which leads to surprising and error-prone results. The strict equality operator === compares both value and type without coercion. There is almost never a good reason to use == in modern JavaScript.

// Loose equality (==) — coerces types before comparing
console.log(5 == "5");       // true  (string "5" converted to number)
console.log(0 == false);     // true  (false converted to 0)
console.log("" == false);    // true  (both coerce to 0)
console.log(null == undefined); // true (special case)
console.log(0 == "");        // true  (confusing!)

// Strict equality (===) — no coercion, must match type AND value
console.log(5 === "5");      // false (number vs string)
console.log(0 === false);    // false (number vs boolean)
console.log("" === false);   // false (string vs boolean)
console.log(null === undefined); // false (different types)
console.log(0 === "");       // false

// Same for inequality
console.log(5 != "5");      // false (loose — coerces, then equal)
console.log(5 !== "5");     // true  (strict — different types)

Explicit Type Conversion

// To String
console.log(String(42));        // "42"
console.log(String(true));      // "true"
console.log((42).toString());   // "42"

// To Number
console.log(Number("42"));     // 42
console.log(Number("3.14"));   // 3.14
console.log(Number(""));       // 0
console.log(Number("hello"));  // NaN
console.log(Number(true));     // 1
console.log(Number(false));    // 0
console.log(parseInt("42px")); // 42 (parses until non-digit)
console.log(parseFloat("3.14em")); // 3.14

// To Boolean
console.log(Boolean(1));       // true
console.log(Boolean(0));       // false
console.log(Boolean("text"));  // true
console.log(Boolean(""));      // false

Template Literals

Template literals (backtick strings) are JavaScript's answer to Python's f-strings. They let you embed expressions inside strings and create multi-line strings easily:

const name = "Alice";
const age = 25;

// String interpolation with ${}
const greeting = `Hello, ${name}! You are ${age} years old.`;
console.log(greeting);
// "Hello, Alice! You are 25 years old."

// Expressions inside ${}
console.log(`Next year you'll be ${age + 1}.`);
console.log(`Is adult: ${age >= 18 ? "yes" : "no"}`);
console.log(`Uppercase: ${name.toUpperCase()}`);

// Multi-line strings (preserves line breaks)
const html = `
<div class="card">
    <h2>${name}</h2>
    <p>Age: ${age}</p>
</div>
`;

// Without template literals, you'd need:
const oldWay = "Hello, " + name + "! You are " + age + " years old.";
// Much harder to read!

Summary

  • Use const by default, let when reassignment is needed, avoid var
  • String: text data — "hello", 'hello', or `hello`
  • Number: integers and decimals — 42, 3.14
  • Boolean: true or false
  • null: intentionally empty — null
  • undefined: declared but not assigned
  • Use typeof to check types, Array.isArray() for arrays
  • Always use === and !== for comparisons (strict equality)
  • Template literals (`${variable}`) are the cleanest way to build strings
🎉
Variables and types mastered!

You now understand how JavaScript stores and handles data. Next up: control flow — making your programs make decisions with if, else, switch, and loops.