Have you ever wondered how objects in JavaScript can “borrow” methods and properties from one another?
The magic behind it is called Prototypal Inheritance. If that sounds confusing, don’t worry. By the end of this article, you’ll understand it as clearly as knowing how a child can inherit traits from a parent.
What is Prototypal Inheritance?🧠
Prototypal inheritance is a way for objects to “inherit” properties and methods from another object. Instead of copying the properties/methods to every new object, JavaScript creates a link between objects.
When one object needs to access a method or property that it doesn’t have, it “asks” its parent object (the prototype) for help. If the parent doesn’t have it, it moves up the chain to the next parent. This is called the prototype chain.
How Does It Work?🛠️
Every object in JavaScript has a hidden link to another object called its prototype. This prototype is like a “parent” object that the current object can borrow methods and properties from.
When you create a new object, JavaScript automatically links it to its prototype. If you try to access a property or method that doesn’t exist in your object, JavaScript will look for it in the prototype.
Simple Explanation: Imagine you have a person called John. If John doesn’t have a “bike”, he might check with his parents. If they don’t have it, he’ll check with his grandparents. This is how the prototype chain works.
Example 1: Basic Prototypal Inheritance✍️
Here’s an example in code to make it clearer.
let parent = {
greet: function() {
console.log("Hello from the parent!");
}
};
let child = Object.create(parent); // child "inherits" from parent
child.greet(); // Hello from the parent!
What’s Happening Here?
- We create an object called parent with a method greet().
- We create child using
Object.create(parent)
, which links child to parent as its prototype. - When we call child.greet(), JavaScript can’t find greet() in the child object, so it “looks up” to its prototype (which is parent) and finds it there.
This is the essence of prototypal inheritance.
Example 2: Constructor Function with Prototypes
While Object.create()
is simple, most developers use constructor functions to create objects.✍️
Here’s an example:
function Animal(name, species) {
this.name = name;
this.species = species;
}
Animal.prototype.eat = function() {
console.log(`${this.name} is eating.`);
};
const dog = new Animal('Buddy', 'Dog');
dog.eat(); // Buddy is eating.
What’s Happening Here?
- We create a constructor function Animal() that initializes two properties: name and species.
- We add a method eat() to Animal.prototype. This way, all objects created using new Animal() will have access to the eat() method.
- When we create dog, it gets its own properties name and species, but it does not have its own copy of the eat() method.
- When we call dog.eat(), JavaScript checks if dog has an eat() method. Since it doesn’t, it looks in the prototype (Animal.prototype) and finds it.
What is the Prototype Chain?🔍
The prototype chain is like a family tree of objects. Here’s how it works:
- When you try to access a property or method on an object, JavaScript first looks at the object itself.
- If it’s not found, it looks at the object’s prototype (parent).
- If it’s still not found, it goes further up the chain to the parent’s prototype.
- This continues until it reaches the end (null).
Example:
let grandparent = { heritage: 'Traditional' };
let parent = Object.create(grandparent);
parent.lastName = 'Smith';
let child = Object.create(parent);
child.firstName = 'John';
console.log(child.firstName); // John (found in child)
console.log(child.lastName); // Smith (inherited from parent)
console.log(child.heritage); // Traditional (inherited from grandparent)
How Does the Chain Work?
- child doesn’t have lastName, so it checks parent (its prototype) and finds it.
- child doesn’t have heritage, so it moves further up to grandparent and finds it there.
This is called prototype chaining.
Key Benefits of Prototypal Inheritance⚙️
- Reusability: You only need to define methods once (on the prototype), and all objects can share them.
- Memory Efficiency: Instead of copying methods to every object, they’re shared from the prototype.
- Dynamic Changes: If you add a new method to the prototype, all child objects immediately have access to it.
Common Mistakes to Avoid🚩
- Overwriting the prototype: Instead of adding methods one-by-one, some people overwrite the whole prototype, which can accidentally remove existing methods.
function Person(name) { this.name = name; } Person.prototype = { // ❌ Bad practice greet: function() { console.log("Hello, " + this.name); } };
Why is this bad? You’re wiping out the default prototype object. If you must do this, be sure to reassign the constructor reference. - Using arrow functions on prototypes: Arrow functions don’t have their own this context, so using them in a prototype method will cause unexpected behavior.
Summary📝
- Prototypal Inheritance allows objects to borrow properties and methods from another object (called a prototype).
- When you create an object, it gets linked to a parent object (the prototype), and this link is called the prototype chain.
- You can create prototypes using Object.create() or constructor functions.
- Inheritance makes your code cleaner, faster, and more efficient because methods are shared rather than duplicated.
Quick Quiz💡
- What happens if you call a method on an object that doesn’t exist on that object?
- How do you create a new object that inherits from another object?
- What is the difference between using
Object.create(parent)
and usingnew Parent()
?
Answers:
- JavaScript looks up the prototype chain.
- Use
Object.create(parent)
or use constructor functions. Object.create(parent)
creates a “pure inheritance link” to the parent, whilenew Parent()
runs the constructor function and initializes properties.
Now that you’ve mastered Prototypal Inheritance, you’re ready to build more complex JavaScript applications. Feel free to Comment! 🚀