Find me on medium
There are multiple design patterns that can be implemented in the JavaScript language, and in this post we will be going over the prototype design pattern.
The prototype design pattern is an object-based creational design pattern.
If you need a recap on the three types of design patterns that they are generally coincided with, here is a little overview:
- Creational Design Patterns
Instead of you having to directly instantiate objects directly, these are the ones that create them for you. The benefit of this approach is that it gives your program a little more flexibility when deciding which objects need to be created for certain situations.
- Behavioral Design Patterns
These patterns are focused on the communication between objects.
- Structural Design Patterns
And lastly, these patterns focus on class and object composition. They can be used to compose interfaces through inheritance and define ways to compose multiple objects in order to achieve new functionality.
If this is your first time learning about the prototype pattern, you now might have some idea of what to expect. But if you don't then it is my job to help clear that mystery for you, my friend.
So what exactly is the prototype pattern, and what does it do?
This pattern's main focus is to help create objects that can be used as blueprints for any object that are created by constructors. It does this through what's called prototypal inheritance.
Since JavaScript has native support for prototypal inheritance, it fortunately becomes naturally easy to work with in the language to the point where you don't really need to learn any new concepts but the syntax itself.
With that said, the prototype design pattern is a very useful strategy--which makes it an important and beneficial way to create programs in JavaScript. We will see why in a bit.
When objects are created through the constructor function and contains the name
property, then further objects created with the same constructor function will also have this same property as shown below:
function Movie(title) {
this.title = title
}
const harryPotter = new Movie('Harry Potter')
const rushHour2 = new Movie('Rush Hour 2')
const fastAndFurious = new Movie('Fast And Furious')
console.log(harryPotter.constructor.name)
console.log(rushHour2.constructor.name)
console.log(fastAndFurious.constructor.name)
It sounds like typical class objects, but in reality it avoids using classes altogether. The prototype design pattern simply creates copies of existing functional objects as opposed to defining brand new objects.
The biggest benefit of using the pattern in JavaScript is the performance boost gained as opposed to object oriented classes. This means that when you define functions inside an object, they will be created by reference. In other words, all child objects will point to the same method instead of creating their own individual copies!
Here's a code example of the pattern in action:
const Warrior = function(name) {
this.name = name
this.hp = 100
}
Warrior.prototype.bash = function(target) {
target.hp -= 15
}
Warrior.prototype.omniSlash = function(target) {
// The target's hp may not be under 50 or this attack will fail on the opponent
if (target.hp < 50) {
return
}
target.hp -= 50
}
const sam = new Warrior('Sam')
const lenardo = new Warrior('Lenardo')
sam.bash(lenardo)
In our code example, we defined a warrior's attack methods by using Warrior.prototype.<method> = function() {...}
. You can see that we instantiated some warriors with the new
keyword so now we are looking at two instances. Both instances set their name
property according to the name
argument that was passed in by the caller.
When we defined the methods bash
and omniSlash
on the prototype as demonstrated, the two separate instances we're looking at are actually referencing the same bash
and omniSlash
functions!
const Warrior = function(name) {
this.name = name
this.hp = 100
}
Warrior.prototype.bash = function(target) {
target.hp -= 15
}
Warrior.prototype.omniSlash = function(target) {
// The target's hp may not be under 50 or this attack will fail on the opponent
if (target.hp < 50) {
return
}
target.hp -= 50
}
const sam = new Warrior('Sam')
const lenardo = new Warrior('Lenardo')
console.log(sam.bash === lenardo.bash) // true
If we instead defined them like this, then they are not the same, so essentially JavaScript has created another copy of the supposedly same method for each instance:
const Warrior = function(name) {
this.name = name
this.hp = 100
this.bash = function(target) {
target.hp -= 15
}
this.omniSlash = function(target) {
// The target's hp may not be under 50 or this attack will fail on the opponent
if (target.hp < 50) {
return
}
target.hp -= 50
}
}
const sam = new Warrior('Sam')
const lenardo = new Warrior('Lenardo')
console.log(sam.bash === lenardo.bash) // false
So if we didn't use the prototype pattern like the last example, how crazy would it be when we instantiate many instances? We would have cloned methods cluttering up memory that essentially do the same exact thing, who don't even need to be copied unless it relies on state inside instances!
Another variation of extending prototypes is a syntax like below:
const Warrior = function(name) {
this.name = name
this.hp = 100
}
Warrior.prototype = {
bash(target) {
target.hp -= 15
},
omniSlash(target) {
// The target's hp may not be under 50 or this attack will fail on the opponent
if (target.hp < 50) {
return
}
target.hp -= 50
},
}
Which is equivalent to:
const Warrior = function(name) {
this.name = name
this.hp = 100
}
Warrior.prototype.bash = function(target) {
target.hp -= 15
}
Warrior.prototype.omniSlash = function(target) {
// The target's hp may not be under 50 or this attack will fail on the opponent
if (target.hp < 50) {
return
}
target.hp -= 50
}
Conclusion
And that concludes the end of this post! I hope you found this to be valuable and look out for more in the future!
Find me on medium
Top comments (6)
..which is equivalent to the code below, a typical class object in modern javascript. I prefer this over modifying prototype objects directly, just because it looks cleaner.
it is just syntactic sugar for above, which is very nice explanation of prototype pattern
I am an experienced java developer trying to learn javascript, this post helped me a lot to understand the inheritance used in javascript, i read several posts, but everyone says "JavaScript is a bit confusing for developers experienced in class-based languages (like Java or C++)" and continue with syntax and examples etc..., but never told about what's the exact difference, here only i got exact answer what i am looking for days. Thanks a lot.
That is awesome, your welcome!
Very informational read, never understood why some experienced devs used prototypes, now I do and plan on doing the same. Thanks a lot for shedding light on the subject
Very glad to hear that!