Variables, Types & Functions
Declaring Variables
JavaScript has three declaration keywords. Use two of them.
const name = "Alice"; // cannot be reassigned
let age = 30; // can be reassigned
// var is legacy — never use it in new code
const is the default. Use let only when you need to reassign. var has function scope instead of block scope, hoists in confusing ways, and allows redeclaration.
const scores = [90, 85, 78];
scores.push(95); // works — const prevents reassignment, not mutation
if (true) {
const x = 10;
let y = 20;
}
// x and y are not accessible here — block-scoped
Primitive Types
JavaScript has seven primitive types. Primitives are immutable and compared by value.
| Type | Example | typeof |
|---|---|---|
| string | "hello" |
"string" |
| number | 42, 3.14, NaN |
"number" |
| boolean | true, false |
"boolean" |
| null | null |
"object" (historic bug) |
| undefined | undefined |
"undefined" |
| symbol | Symbol("id") |
"symbol" |
| bigint | 9007199254740993n |
"bigint" |
JavaScript has one number type: 64-bit IEEE 754 floating point. 0.1 + 0.2 produces 0.30000000000000004. For integers beyond Number.MAX_SAFE_INTEGER, use BigInt.
undefined means a variable was declared but not assigned. null means an intentional absence of value. Symbols create unique identifiers — two symbols are never equal, even with the same description.
Objects & Arrays
Everything that is not a primitive is an object. Objects are key-value pairs. Arrays are ordered lists (and are also objects).
const user = { name: "Alice", age: 30, roles: ["admin", "editor"] };
console.log(user.name); // "Alice"
console.log(user["age"]); // 30
console.log(user.roles[0]); // "admin"
const colors = ["red", "green", "blue"];
colors.push("yellow");
console.log(colors.length); // 4
Reference vs Value
Primitives are compared by value. Objects are compared by reference.
const a = { name: "Alice" };
const b = { name: "Alice" };
const c = a;
console.log(a === b); // false — different objects
console.log(a === c); // true — same reference
Functions
Declarations, Expressions & Arrows
// Declaration — hoisted, can be called before it appears
function greet(name) {
return `Hello, ${name}!`;
}
// Expression — not hoisted
const greetExpr = function(name) {
return `Hello, ${name}!`;
};
// Arrow — shorter, no own this
const add = (a, b) => a + b;
const square = x => x * x;
const getUser = () => ({ name: "Alice", age: 30 }); // object needs parens
Default Parameters
function createUser(name, role = "viewer") {
return { name, role };
}
console.log(createUser("Alice")); // { name: "Alice", role: "viewer" }
console.log(createUser("Bob", "admin")); // { name: "Bob", role: "admin" }
Template Literals
Backtick strings support interpolation and multiline content.
const name = "Alice";
const age = 30;
const message = `${name} is ${age} years old.
She will be ${age + 1} next year.`;
Destructuring
Object Destructuring
const user = { name: "Alice", age: 30, role: "admin" };
const { name, age } = user; // basic
const { name: userName, role: userRole } = user; // renaming
const { name: n, country = "Unknown" } = user; // default values
Array Destructuring
const colors = ["red", "green", "blue"];
const [first, second] = colors; // "red", "green"
const [, , third] = colors; // skip to "blue"
let a = 1, b = 2;
[a, b] = [b, a]; // swap
Destructuring in Function Parameters
function formatUser({ name, age, role = "viewer" }) {
return `${name} (${age}) — ${role}`;
}
Spread & Rest Operators
The ... syntax does two things depending on context.
Spread: Expanding
const nums = [1, 2, 3];
const more = [...nums, 4, 5]; // [1, 2, 3, 4, 5]
const user = { name: "Alice", age: 30 };
const updated = { ...user, age: 31, role: "admin" };
// { name: "Alice", age: 31, role: "admin" }
Spread creates a shallow copy. Nested objects are still shared by reference.
Rest: Collecting
function sum(...numbers) {
return numbers.reduce((total, n) => total + n, 0);
}
console.log(sum(1, 2, 3, 4)); // 10
const { name, ...rest } = { name: "Alice", age: 30, role: "admin" };
console.log(rest); // { age: 30, role: "admin" }
const [first, ...remaining] = [1, 2, 3, 4];
console.log(remaining); // [2, 3, 4]
Common Pitfalls
Using var instead of const/let. var is function-scoped, which causes bugs in loops.
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0);
}
// Prints: 3, 3, 3 — not 0, 1, 2. Use let to fix.
Confusing == with ===. Always use ===. The == operator coerces types: 0 == "" is true, 0 === "" is false.
Mutating const objects and thinking they are frozen. const prevents reassignment, not mutation. Use Object.freeze() for shallow immutability.
Forgetting that typeof null returns "object". Check for null explicitly with value === null.
Accidentally creating global variables. Assigning to a variable without declaring it creates a global. Strict mode ("use strict") prevents this.
Key Takeaways
- Use
constby default,letwhen you need reassignment, nevervar. - JavaScript has seven primitive types. Everything else is an object.
- Functions come in three forms: declarations (hoisted), expressions, and arrow functions.
- Template literals with backticks replace string concatenation.
- Destructuring extracts values from objects and arrays into clean variable bindings.
- The spread operator expands iterables; the rest operator collects arguments.
- Always use
===for comparisons. Always use strict mode.