1 — From Object Literals to Blueprints
Session 01 showed you object literals — one object, written by hand. That's fine for a single cart or a single config. But what happens when you need fifty users, each with the same shape and the same methods? Copy-pasting the literal fifty times is not a plan.
A class is a blueprint for objects. You define the shape and behaviour once; then you stamp out as many independent objects from it as you need. Think of the class as a cookie cutter and each object as a cookie — same shape, but each one is separate and can hold its own state (sprinkles, icing — or in code terms, its own property values).
// Works, but doesn't scale — every user repeats the same shape and logic const user1 = { name: 'Alice', role: 'admin', describe() { return `${this.name} (${this.role})`; } }; const user2 = { name: 'Bob', role: 'editor', describe() { return `${this.name} (${this.role})`; } }; // ...and again, and again, for every user you create
2 — Defining Your First Class
A class declaration uses the class keyword, PascalCase by convention (User, not user), and a special method called constructor() that runs every time you create a new instance.
/** * Class declaration: PascalCase by convention */ class User { constructor(name, role) { this.name = name; // instance property this.role = role; // instance property } describe() { // instance method return `${this.name} (${this.role})`; } } const user1 = new User('Alice', 'admin'); const user2 = new User('Bob', 'editor'); console.log(user1.describe()); // "Alice (admin)" console.log(user2.describe()); // "Bob (editor)"
Same blueprint, two independent objects. Changing user1.name has zero effect on user2 — each instance owns its own copy of the instance properties set inside the constructor.
What new actually does
When you write new User(...), four things happen in order:
- A brand-new, empty object is created
- That object's internal prototype is linked to User.prototype (more on this in Session 03)
- The constructor() runs, with this bound to the new object
- The new object is returned automatically — you don't write return yourself
3 — Class Fields: Properties Without a Constructor Line
Modern JavaScript (ES2022+) lets you declare instance properties directly in the class body, skipping the this.x = x boilerplate when a property has a fixed default or doesn't depend on a constructor argument.
class ShoppingCart { items = []; // class field — fresh array per instance discountRate = 0.1; // class field with a default value constructor(owner) { this.owner = owner; // still fine to set some props in the constructor } addItem(name, price) { this.items.push({ name, price }); } total() { const sum = this.items.reduce((a, i) => a + i.price, 0); return sum * (1 - this.discountRate); } } const cart = new ShoppingCart('Alice'); cart.addItem('Keyboard', 80); console.log(cart.total()); // 72
The critical detail: items = [] as a class field runs per instance. Each new ShoppingCart gets its own fresh empty array — they don't share one array between every cart. That's exactly the encapsulation win from Session 01, now formalized by the class.
4 — Instance Methods vs Object-Literal Methods
A method written inside a class body looks similar to the shorthand method syntax from Session 01 — but there's a meaningful difference in where it lives.
class Point { constructor(x, y) { this.x = x; this.y = y; } distanceFromOrigin() { return Math.sqrt(this.x ** 2 + this.y ** 2); } } const p1 = new Point(3, 4); const p2 = new Point(6, 8); // p1 and p2 each have their own x/y... console.log(p1.x === p2.x); // false — different own properties // ...but they SHARE the exact same distanceFromOrigin function console.log(p1.distanceFromOrigin === p2.distanceFromOrigin); // true
Methods defined in a class body are placed once on Point.prototype and shared by every instance — they are not recreated per object the way class fields are. Object-literal methods, by contrast, belong to that one specific object. This is a memory-efficiency detail today; in Session 03 it becomes the key to understanding what class is actually doing behind the scenes.
15-Minute Review — Session 02
Stop the session timer and switch to the review timer in the sidebar. Answer these questions from memory — then check.
Q1 — What is the main reason to use a class instead of writing object literals by hand?
Q2 — Which special method runs automatically every time you create a new instance with new?
Q3 — You declare items = [] as a class field. What happens when you create two instances of that class?
Q4 — Two instances of the same class, p1 and p2. What is true about their instance methods (e.g. p1.describe vs p2.describe)?