Lesson 3 of 5
Objects, prototypes and classes
2 min read
Prototypal inheritance
Every object has a hidden link ([[Prototype]]) to another object. When you read a property that isn't on the object, JavaScript looks up the prototype chain until it finds it or reaches null.
const animal = { speak() { return `${this.name} makes a sound`; } };
const dog = Object.create(animal);
dog.name = "Rex";
dog.speak(); // found on animal via the chainArrays get map, filter and friends from Array.prototype; that's why every array has them.
Classes are syntax over prototypes
class Account {
#balance = 0; // truly private field
constructor(owner) { this.owner = owner; }
deposit(amount) {
if (amount <= 0) throw new Error("Amount must be positive");
this.#balance += amount;
return this; // allows chaining
}
get balance() { return this.#balance; }
static compare(a, b) { return a.balance - b.balance; }
}
class SavingsAccount extends Account {
constructor(owner, rate) { super(owner); this.rate = rate; }
addInterest() { return this.deposit(this.balance * this.rate); }
}Methods live on Account.prototype, shared by all instances, not copied into each object.
Copying objects
const copy = { ...original }; // shallow: nested objects are still shared
const deep = structuredClone(original); // deep copy (modern browsers and Node 17+)JSON.parse(JSON.stringify(x)) also deep-copies but loses dates, undefined, functions, Maps and Sets.
Useful built-ins
Object.keys / values / entries,Object.fromEntriesObject.freeze(shallow, makes properties read-only)Map(any key type, keeps insertion order, has.size) vs plain object (string/symbol keys)Setfor unique values:[...new Set(arr)]removes duplicatesWeakMapfor metadata about objects without preventing garbage collection
Array methods you must know cold
const orders = [{ city: "Pune", total: 500 }, { city: "Delhi", total: 300 }, { city: "Pune", total: 200 }];
orders.filter((o) => o.total > 250); // keep some
orders.map((o) => o.total); // transform each
orders.reduce((sum, o) => sum + o.total, 0); // 1000: fold into one value
orders.find((o) => o.city === "Delhi"); // first match or undefined
orders.some((o) => o.total > 400); // true
orders.every((o) => o.total > 100); // true
[...orders].sort((a, b) => b.total - a.total); // sort copies; sort() mutates!
// group by city
orders.reduce((acc, o) => { (acc[o.city] ??= []).push(o); return acc; }, {});Know which mutate (push, pop, splice, sort, reverse) and which return new arrays (map, filter, slice, concat, toSorted).
Check yourself
- What is the prototype chain?
- What's the difference between a shallow and a deep copy?
- Implement
groupBywithreduce.
Sign up free to save your progress.