Introduction
JavaScript is a versatile programming language known for its unique approach to object-oriented programming through prototypal inheritance. Unlike traditional class-based languages, JavaScript utilizes a prototype-based model that allows objects to inherit properties and behaviors from other objects. This mechanism is at the heart of JavaScript's flexibility and power. In this blog, we'll dive deep into prototypal inheritance, focusing on the mysterious __proto__
property and Object.prototype
.
Prototypal Inheritance: A Foundation
The "prototype" is a fundamental concept related to object-oriented programming and inheritance. It refers to an object that serves as a template or blueprint for creating other objects.
- Prototype Object: A prototype is like a model that other objects can copy. Imagine it as a blueprint for creating things. In JavaScript, almost everything is built based on these prototypes. They create a chain, where one prototype can be the basis for another, and this can keep going.
For example:
Assign an array of values to the variable arr after it has been declared. We notice something known as a prototype if we attempt to console it.
Prototype Chain: This is like a line of connected prototypes. If something doesn't have a piece of information, it asks the prototype it's connected to. If that prototype doesn't have it, it asks its own prototype, and so on, like a chain of help.
We can see all the array methods right here inside the prototype. But if we pay closer attention, we can once more see a prototype inside of a prototype, but the inside prototype has methods that are of an object type rather than an array.
Why is that? Understanding
__proto__
__proto__
is a non-standard property in JavaScript that allows access to an object's prototype, enabling inheritance of properties and methods. It's used to query and manipulate the prototype relationship between objects.
Step 1: Exploring Array Prototype
Start by examining
Array.prototype
. This special blueprint holds methods tailored specifically for arrays, likepush()
,pop()
, and many more.Printing
Array.prototype
will display these array-related methods that are available for all arrays.
Step 2: Array and its Prototype Connection
Create an array named
arr
. This array has a connection to Array's prototype object through a property called__proto__
.Printing
arr.__proto__
reveals a connection to the same methods we saw inArray.prototype
.
Step 3: The Prototype Chain Mystery
The question arises: If
array.__proto__
already holds the array methods fromArray.prototype
, why is there another__proto__
attached toarray.__proto__
?This second
__proto__
forms a chain to another prototype object. It's like a bridge to a new set of methods.
Step 4: Journey to Object Prototype
This second
__proto__
leads toObject.prototype
. This blueprint has methods common to all JavaScript objects, liketoString()
andhasOwnProperty()
.When you look at
Object.prototype
, you'll recognize the methods that the second__proto__
holds.
Step 5: Expanding the Chain
The second
__proto__
in the chain contains methods inherited fromObject.prototype
.Wondering what happens if you continue this chain? Imagine adding one more
__proto__
afterarray.__proto__.__proto__
.This additional
__proto__
leads nowhere—it points tonull
.
In Summary:
Array.prototype
contains methods tailored for arrays.array.__proto__
connects to the array methods inArray.prototype
.The second
__proto__
chained toarray.__proto__
connects toObject.prototype
, offering general object methods.The methods in
Object.prototype
are recognizable because they match those in the second__proto__
.If you extend the chain with one more
__proto__
, it will eventually lead tonull
.
This step-by-step breakdown highlights how the prototype chain works, connecting objects and their methods, ultimately reaching a point where the chain ends.
Modifying Prototypes: It's like adding new features to all things made from a certain template. If you change the prototype, everything that was made from that prototype will have the new feature, but not the ones made before the change.
Step 1: Establishing Prototype Inheritance
Start by having two objects:
obj1
andobj2
.Set up a prototype inheritance link:
obj2.__proto__ = obj1
.Now,
obj2
inherits properties and methods fromobj1
.
Step 2: Accessing Inherited Methods
Suppose
obj1
has a method calledgreet()
.When you call
obj2.greet()
, JavaScript checks ifgreet()
exists inobj2
.Since it's not found in
obj2
, the prototype chain is used to findgreet()
inobj1
.As a result,
obj2
can access and use thegreet()
method defined inobj1
.
Step 3: Sharing Properties Between Objects
Consider that both
obj1
andobj2
have a property calledname
.When you call
obj2.greet()
, thegreet()
method fromobj1
is executed.Inside the method, the
name
property is fetched fromobj2
since the method is executed within the context ofobj2
.
Step 4: Seeking Properties Through the Chain
Now, imagine
obj1
has a unique property calledprofession
.If you attempt to access
obj2.profession
, JavaScript starts by looking forprofession
inobj2
.Since it's not found in
obj2
, the prototype chain is followed, leading toobj1
.JavaScript finds the
profession
property inobj1
, allowing you to access it viaobj2
.
- Built-in Prototypes: JavaScript has a bunch of pre-made templates. For example, every object you make, whether a regular one, an array, or a function, is based on a common template called
Object.prototype
. Arrays have some extra stuff that comes fromArray.prototype
, like special ways to work with lists of things. Functions have their own special things too, fromFunction.prototype
.
Conclusion
Understanding prototypal inheritance is essential for any JavaScript developer to write efficient and maintainable code. It enables the creation of complex data structures and promotes the reuse of code, fostering a deeper understanding of how JavaScript works behind the scenes.