๐ฆ What is a variable?
A labeled box that stores a value so you can use it later.
JavaScript gives you three ways to create one: var, let, and const.
js
var oldWay = "I still work but I'm outdated";
let score = 10;
score = 20; // โ
totally fine, let allows you to reassign.
const birthYear = 2003;
// birthYear = 2004; // ๐ซ throws an error, const doesn't allow reassignment
๐ฐ๏ธ var โ old-school, function-scoped,it leaks out of blocks like if statements and loops.Var usually causes weird bugs. Don't use it in new code.
โ let โ modern, block-scoped, use when the value will change.
๐ const โ modern, block-scoped, use by default unless you know the value needs to change.
๐ง Scope: where a variable is allowed to "live".
let and const being block-scoped means โ they only exist inside the { } they were created in.
js
if (true) {
var leaky = "I escape the block!";
const trapped = "I stay inside the block";
let alsoTrapped = "Me too, I stay inside the block";
// โ
all three work fine HERE, still inside the block
console.log(leaky); // "I escape the block!"
console.log(trapped); // "I stay inside the block"
console.log(alsoTrapped); // "Me too, I stay inside the block"
}
// Outside the block now:
console.log(leaky); // โ
"I escape the block!" โ var doesn't respect the block
console.log(trapped); // โ ReferenceError โ const is block-scoped
console.log(alsoTrapped); // โ ReferenceError โ let is block-scoped too
๐ Takeaway: let and const behave identically on scope โ both are trapped inside their block. They only differ on reassignment (next section).
๐พ The const bottle analogy โ identity vs. contents
const locks the name's connection to a specific bottle โ not what's poured inside that bottle.
Picture three layers:
The name (aqua) โ the label
The bottle โ the actual container in memory
The contents โ whatever liquid is inside right now
js
const aqua = { content: "water" };
This line only runs once โ it creates a bottle, fills it with water, and permanently glues the name aqua to that one bottle. It's a snapshot of the starting contents, not a permanent rule about what the bottle must always hold.
You CAN refill the same bottle โ editing contents is always allowed, even with const:
js
aqua.content = "wine";
console.log(aqua); // { content: "wine" } โ same bottle, just refilled
Same bottle, same name, only the liquid inside changed. aqua never stopped pointing at that exact bottle.
You CANNOT swap in a whole new bottle โ that's reassignment, and const blocks it:
js
aqua = { content: "juice" }; // โ error โ this is a brand NEW bottle, not a refill
This fails because you're not pouring juice into the existing bottle โ you're trying to make the name aqua point to a completely different container. const only ever locked the name-to-bottle connection, and this line tries to break that connection.
๐ One-line summary: const = "this name will always point to this exact bottle" โ not "this bottle can never change what's inside it."
The same logic applies to arrays, since arrays are objects too:
js
const fruits = ["mango", "banana"];
fruits.push("avocado"); // โ
allowed โ editing contents
fruits[0] = "pineapple"; // โ
allowed โ editing contents
// fruits = ["new", "list"]; // โ error โ swaps the whole array reference
๐ let โ same bottle rules, but the name can also switch bottles
let allows everything const allows on contents, plus it lets the name walk away and point at a completely different bottle:
js
let aqua = { content: "water" };
aqua.content = "wine"; // โ
allowed โ same bottle, refilled
console.log(aqua); // { content: "wine" }
aqua = { content: "juice" }; // โ
allowed โ a whole NEW bottle, same name reused
console.log(aqua); // { content: "juice" }
The two differences, side by side:
Refill the same bottle (edit contents)? Swap in a whole new bottle (reassign)?
const โ
Yes โ No
let โ
Yes โ
Yes
๐ One-line summary: both let you change what's inside the bottle. The only difference is whether the name is allowed to walk away and grab a different bottle entirely โ const says no, let says go for it.
๐ Hoisting
Before your code runs, JavaScript does a pass over the script and "hoists" (lifts) variable declarations to the top of their scope โ but not the value assignment. Only the declaration moves up; the assignment stays where you wrote it.
js
console.log(a); // undefined โ not an error!
var a = 5;
console.log(a); // 5
Behind the scenes, this is treated like:
js
var a; // declaration hoisted to the top, auto-set to undefined
console.log(a); // undefined
a = 5; // assignment happens where you originally wrote it
console.log(a); // 5
let and const get hoisted too โ but they don't default to undefined. Instead they sit in the Temporal Dead Zone (TDZ): the variable technically exists, but touching it before its declaration line is illegal.
js
console.log(b); // โ ReferenceError: Cannot access 'b' before initialization
let b = 5;
js
{
// ๐ง TDZ starts here โ b "exists" but is untouchable
console.log(b); // โ error, still in the dead zone
let b = 5; // ๐ง TDZ ends here
console.log(b); // โ
5, totally fine now
}
๐ One-line summary: var gets hoisted and pre-filled with undefined. let/const get hoisted but stay locked in the dead zone until your code actually reaches their declaration line.
๐ Redeclaring
js
var x = 1;
var x = 2; // โ
allowed, messy but works
let y = 1;
// let y = 2; // โ error โ can't redeclare a let in the same scope
๐ฏ The verdict on all three: default to const. Switch to let only when you know the value (or the whole bottle) needs to change. Avoid var entirely in new code.
๐ท๏ธ What is a data type?
JavaScript sorts types into two families: primitive (simple, single values) and reference (complex, made of multiple values).
๐งฑ Primitive types
js
let str = "hello"; // ๐ค String
let num = 42; // ๐ข Number
let isTrue = true; // โ
Boolean
let nothing = null; // ๐ซ Null โ "empty on purpose"
let notSet; // โ Undefined โ "not given a value yet"
let big = 123n; // ๐ BigInt
let sym = Symbol("id"); // ๐ฎ Symbol โ guaranteed-unique value
๐งฉ Reference types
js
let person = { name: "Brian", age: 22 }; // ๐๏ธ Object
let fruits = ["mango", "banana"]; // ๐ Array (secretly an object)
function greet() {} // โ๏ธ Function (also technically an object)
โก Special number values
js
console.log(1 / 0); // Infinity
console.log(-1 / 0); // -Infinity
console.log("abc" * 2); // NaN
console.log(typeof NaN); // "number" ๐คฏ
๐ Famous JS quirk: typeof null returns "object" โ a decades-old bug that's now permanent. Just know it exists.
๐ Checking types
js
console.log(typeof "hi"); // "string"
console.log(typeof 5); // "number"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof {}); // "object"
console.log(typeof []); // "object" โ arrays are secretly objects
console.log(typeof function(){}); // "function"
๐ Dynamic typing
js
let thing = "hello"; // starts as a String
thing = 5; // now it's a Number, JS doesn't complain
โ๏ธ What is an operator?
1๏ธโฃ Arithmetic
js
let total = 5 + 3; // 8
let diff = 5 - 3; // 2
let product = 5 * 3; // 15
let split = 5 / 3; // 1.666...
let leftover = 5 % 3; // 2 โ modulus
let power = 5 ** 2; // 25 โ exponent
2๏ธโฃ Assignment
js
let x = 10;
x += 5; // 15
x -= 3; // 12
x = 2; // 24
x /= 4; // 6
x %= 5; // 1
x *= 2; // 1
3๏ธโฃ Comparison
js
console.log(5 == "5"); // true โ loose, ignores type
console.log(5 === "5"); // false โ strict, checks type too โ
prefer this
console.log(5 != "5"); // false
console.log(5 !== "5"); // true โ
prefer this
console.log(5 > 3); // true
console.log(5 < 3); // false
console.log(5 >= 5); // true
console.log(5 <= 4); // false
4๏ธโฃ Logical
js
let hasLaptop = true;
let hasWifi = false;
console.log(hasLaptop && hasWifi); // false โ AND
console.log(hasLaptop || hasWifi); // true โ OR
console.log(!hasLaptop); // false โ NOT
5๏ธโฃ Increment / decrement
js
let count = 5;
count++; // 6
count--; // 5
let n = 5;
console.log(n++); // logs 5, THEN increments
console.log(++n); // increments FIRST, then logs 7
6๏ธโฃ Ternary
js
let age = 20;
let canVote = age >= 18 ? "Yes" : "No"; // "Yes"
7๏ธโฃ Nullish coalescing (??)
js
let username = null;
let displayName = username ?? "Guest"; // "Guest"
let score = 0;
console.log(score ?? 100); // 0 โ kept, since 0 isn't null/undefined
console.log(score || 100); // 100 โ || wrongly treats 0 as falsy โ ๏ธ
8๏ธโฃ Optional chaining (?.)
js
let user = { profile: { name: "Brian" } };
console.log(user?.profile?.name); // "Brian"
console.log(user?.settings?.theme); // undefined โ no crash ๐
9๏ธโฃ Bitwise
js
console.log(5 & 1); // 1 โ AND
console.log(5 | 1); // 5 โ OR
console.log(5 ^ 1); // 4 โ XOR
console.log(~5); // -6 โ NOT
console.log(5 << 1); // 10 โ shift left
console.log(5 >> 1); // 2 โ shift right
๐ Keyword operators
js
console.log(typeof "hi"); // "string"
let arr = [1, 2, 3];
console.log(arr instanceof Array); // true
let obj = { name: "Brian" };
console.log("name" in obj); // true
delete obj.name;
console.log(obj); // {}
1๏ธโฃ1๏ธโฃ Comma operator
js
let a = (1 + 2, 3 + 4); // a = 7 โ only the LAST value is kept
๐ TL;DR
Category Members
๐ค Declarations var, let, const
๐งฑ Primitive types String, Number, Boolean, Null, Undefined, BigInt, Symbol
๐งฉ Reference types Object, Array, Function
โ๏ธ Operators Arithmetic, Assignment, Comparison, Logical, Increment/Decrement, Ternary, Nullish Coalescing, Optional Chaining, Bitwise, Keyword ops, Comma
Top comments (0)