Reuse
Prototypes and Object-Oriented Programming
Object-oriented programming (OOP) is a way of organizing code using objects, where each object holds both data and behavior together.
In JavaScript, OOP is prototype-based, not class-based like some other languages.
Even when you use the class keyword, JavaScript is still secretly using prototype chains behind the scenes.
Why OOP and Prototypes Matter
Section titled “Why OOP and Prototypes Matter”Structure
Scalability
Performance
Core Idea: Prototype Chain
Section titled “Core Idea: Prototype Chain”Property Lookup Rule
Section titled “Property Lookup Rule”- JavaScript first checks the object itself.
- If the property is not found there -> it checks the prototype.
- It keeps moving upward through the chain like this.
- It finally stops once it reaches
null.
Prototype Basics
Section titled “Prototype Basics”const animal = { speak() { return "Some sound"; },};
const dog = Object.create(animal);dog.name = "Bruno";
console.log(dog.speak());Internal Resolution
Section titled “Internal Resolution”Property Lookup Behavior
Section titled “Property Lookup Behavior”const baseUser = { role: "user" };const admin = Object.create(baseUser);
admin.name = "Riya";
console.log(admin.name); // ownconsole.log(admin.role); // prototypeShadowing
Section titled “Shadowing”admin.role = "admin";Now:
console.log(admin.role); // adminThis is called shadowing, it simply means that admin now has its own role property, and this new one “hides” the one coming from the prototype.
__proto__ vs prototype vs [[Prototype]]
Section titled “__proto__ vs prototype vs [[Prototype]]”__proto__
This is the actual link to the parent object, while your code is running.
prototype
This is a property that belongs to a constructor function.
[[Prototype]]
This is an internal slot used by the JavaScript engine itself.
function Person() {}const p = new Person();
p.__proto__ === Person.prototype; // trueConstructor Functions
Section titled “Constructor Functions”function Person(name) { this.name = name;}
Person.prototype.greet = function () { return `Hi ${this.name}`;};Memory Model
Section titled “Memory Model”Instance vs Prototype Mutation
Section titled “Instance vs Prototype Mutation”function User(name) { this.name = name;}
User.prototype.role = "user";
const u1 = new User("A");const u2 = new User("B");
u1.role = "admin";
console.log(u1.role); // adminconsole.log(u2.role); // userExplanation
Section titled “Explanation”u1.role-> here, a new property is created directly onu1itself.u2.role-> this one is still coming from the shared prototype.
Getter and Setter
Section titled “Getter and Setter”const user = { first: "Sahil", last: "Kumar",
get fullName() { return `${this.first} ${this.last}`; },
set fullName(value) { [this.first, this.last] = value.split(" "); },};A getter lets you read a value as if it were a normal property, but it actually runs a small function behind the scenes. A setter does the same thing, but for writing (setting) a value.
console.log(user.fullName);user.fullName = "John Doe";Prototype + Getter
Section titled “Prototype + Getter”function Person(name) { this.name = name;}
Person.prototype = { get display() { return `Name: ${this.name}`; },};hasOwnProperty vs in
Section titled “hasOwnProperty vs in”const obj = { a: 1 };
obj.hasOwnProperty("a"); // true"a" in obj; // trueDifference
Section titled “Difference”hasOwnProperty-> this only checks the object’s own properties.in-> this also checks properties coming from the prototype chain.
Class Syntax
Section titled “Class Syntax”class Vehicle { constructor(brand) { this.brand = brand; }
start() { return `${this.brand} started`; }}Behind the Scene
Section titled “Behind the Scene”Vehicle.prototype.start = function () {};Even though this looks like a normal class, JavaScript is actually still attaching the start method onto the prototype behind the scenes, just like before.
Inheritance
Section titled “Inheritance”class Animal { speak() { return "sound"; }}
class Dog extends Animal { bark() { return "woof"; }}OOP Concepts
Section titled “OOP Concepts”- Encapsulation -> this means bundling data and methods together inside one place.
- Inheritance -> this means reusing logic from another object or class.
- Polymorphism -> this means the same method name can behave differently depending on the object.
- Abstraction -> this means hiding away the complicated details that you do not need to see.
Encapsulation
Section titled “Encapsulation”class BankAccount { #balance = 0;
deposit(a) { this.#balance += a; }
getBalance() { return this.#balance; }}Here, #balance is a private field. This means it can only be accessed from inside the class itself, not from outside it.
Polymorphism
Section titled “Polymorphism”class Shape { area() { return 0; }}this in Prototypes
Section titled “this in Prototypes”User.prototype.say = function () { return this.name;};Object.create vs new
Section titled “Object.create vs new”const obj1 = Object.create(proto);const obj2 = new Constructor();Object.create lets you directly set the prototype of a new object. new instead calls a constructor function to build the object for you.
Changing Prototype
Section titled “Changing Prototype”Object.setPrototypeOf(obj, proto);Shared Reference Bug
Section titled “Shared Reference Bug”function Test() {}Test.prototype.arr = [];
const a = new Test();const b = new Test();
a.arr.push(1);
console.log(b.arr); // [1]This happens because arr lives on the shared prototype, not on each individual object. So when a changes it, b sees the change too, since they are both looking at the exact same array.
OOP + Async
Section titled “OOP + Async”class ApiClient { async get() { return fetch("/api").then((r) => r.json()); }}