JavaScript > Prototypes and Inheritance > Prototype Chain > Prototype inheritance
Understanding Prototype Inheritance in JavaScript
This example demonstrates how prototype inheritance works in JavaScript, allowing objects to inherit properties and methods from their prototypes. We'll cover the creation of objects, setting up the prototype chain, and accessing inherited properties.
Basic Prototype Inheritance
This code demonstrates the core concept of prototype inheritance. We define an Crucially, The Animal
constructor with a sayName
method attached to its prototype. Then, we define a Dog
constructor which 'inherits' from Animal
. Dog.prototype = Object.create(Animal.prototype);
establishes the inheritance. It creates a new object whose prototype is Animal.prototype
and assigns it to Dog.prototype
. This means instances of Dog
can access methods defined on Animal.prototype
. We then need to set the Dog.prototype.constructor
to Dog
. Finally, we add a method specific to Dog
named bark
.Animal.call(this, name)
ensures that the Animal
constructor is called in the context of the Dog
instance, correctly initializing the name
property. The instanceof
operator confirms the inheritance relationship.
// Define a constructor function
function Animal(name) {
this.name = name;
}
// Add a method to the Animal prototype
Animal.prototype.sayName = function() {
return 'My name is ' + this.name;
};
// Create a new constructor function that inherits from Animal
function Dog(name, breed) {
Animal.call(this, name); // Call the Animal constructor to set the 'name' property
this.breed = breed;
}
// Set Dog's prototype to be a new Animal object, establishing the inheritance
Dog.prototype = Object.create(Animal.prototype);
// Set the constructor property back to Dog
Dog.prototype.constructor = Dog;
// Add a method specific to Dog
Dog.prototype.bark = function() {
return 'Woof!';
};
// Create instances
const animal1 = new Animal('Generic Animal');
const dog1 = new Dog('Buddy', 'Golden Retriever');
// Test the inheritance
console.log(animal1.sayName()); // Output: My name is Generic Animal
console.log(dog1.sayName()); // Output: My name is Buddy (inherited from Animal)
console.log(dog1.bark()); // Output: Woof! (specific to Dog)
console.log(animal1.bark()); // Output: animal1.bark is not a function
console.log(dog1 instanceof Animal); // true
console.log(dog1 instanceof Dog); // true
console.log(animal1 instanceof Dog); // false
Concepts Behind the Snippet
new
keyword.prototype
property, which is an object. When you create an object using new
, the newly created object's internal prototype (__proto__
, though not directly accessible in modern JavaScript - use Object.getPrototypeOf()
) is set to the constructor function's prototype
object.Object.prototype
, which has null
as its prototype.Object.create()
: This method creates a new object, using an existing object as the prototype of the newly created object. It's the preferred way to establish inheritance in modern JavaScript as it avoids calling the parent constructor directly when setting up the prototype chain.Animal.call(this, name)
: Calls the Animal
constructor setting the context (this
) to the current Dog instance and passing the 'name' argument to the Animal function. This allows the Dog to inherit the properties/logic handled by the Animal constructor
Real-Life Use Case
Prototype inheritance is commonly used in libraries and frameworks to create reusable components. For example, a UI library might define a base Component
class with common methods for rendering and handling events. Specific UI elements like Button
, TextField
, and Dropdown
can then inherit from Component
, adding their own specific functionality while reusing the common logic. This promotes code reuse and reduces duplication.
Best Practices
Object.create()
for Prototype Assignment: Avoid directly assigning a new instance of the parent class to the prototype. Object.create()
is cleaner and avoids potentially unwanted side effects from the parent constructor.constructor
property to point back to the correct constructor function. This is important for accurate type checking and object instantiation.class
keyword) provide a more syntactic sugar for defining inheritance relationships, making the code more readable and maintainable. However, they still rely on prototype inheritance under the hood.
Interview Tip
Be prepared to explain the difference between prototype inheritance and classical inheritance (as found in languages like Java or C++). JavaScript uses prototypal inheritance, where objects inherit directly from other objects. Classical inheritance uses classes, and objects inherit from classes. Also, be ready to explain the prototype chain, how it works, and why it's important.
When to Use Them
Prototype inheritance is fundamental to JavaScript and is used extensively behind the scenes. You'll implicitly use it whenever you create objects and functions. Explicitly managing the prototype chain becomes important when you're designing reusable components or creating complex object hierarchies. Use it when you want to share common functionality between objects of different types.
Memory footprint
With prototypal inheritance, methods defined on the prototype are shared among all instances of the object. This means that each object doesn't need to store its own copy of the methods, resulting in a smaller memory footprint compared to classical inheritance where each object might have its own copy of the methods.
Alternatives
While prototypal inheritance is a core feature of JavaScript, there are alternative patterns and features that can be used to achieve similar goals:
Pros
Cons
FAQ
-
What is the prototype chain?
The prototype chain is a series of links between objects in JavaScript. When you try to access a property on an object, JavaScript first looks for the property on the object itself. If it doesn't find it, it looks at the object's prototype, and so on, up the chain until it reaches
Object.prototype
. If the property is still not found, it returnsundefined
. -
Why is it important to set the constructor property after modifying the prototype?
Setting the
constructor
property ensures that theconstructor
property of the prototype object points back to the correct constructor function. This is important for accurate type checking and object instantiation. For example,instanceof
relies on theconstructor
property to determine the type of an object. -
What is the difference between
Object.create()
and usingnew
with the parent constructor?
Object.create(Parent.prototype)
creates a new object withParent.prototype
as its prototype, without invoking theParent
constructor. Usingnew Parent()
creates a new instance ofParent
, which can have side effects from theParent
constructor.Object.create()
is generally preferred for setting up inheritance as it's cleaner and avoids unwanted side effects.