Any JavaScript developer has either seen the keyword prototype, confused by the prototypical inheritance, or implemented prototypes in their code. The Prototype design pattern relies on the JavaScript prototypical inheritance. The prototype model is used mainly for creating objects in performance-intensive situations.
The objects created are clones (shallow clones) of the original object that are passed around. One use case of the prototype pattern is performing an extensive database operation to create an object used for other parts of the application. If another process needs to use this object, instead of having to perform this substantial database operation, it would be advantageous to clone the previously created object.
Prototype Design Pattern on Wikipedia
This UML describes how a prototype interface is used to clone concrete implementations.
To clone an object, a constructor must exist to instantiate the first object. Next, by using the keyword prototype variables and methods bind to the object’s structure. Let’s look at a basic example:
var TeslaModelS = function() {
this.numWheels = 4;
this.manufacturer = 'Tesla';
this.make = 'Model S';
}
TeslaModelS.prototype.go = function() {
// Rotate wheels
}
TeslaModelS.prototype.stop = function() {
// Apply brake pads
}
The constructor allows the creation of a single TeslaModelS object. When a creating new TeslaModelS object, it will retain the states initialized in the constructor. Additionally, maintaining the function go and stop is easy since we declared them with prototype. A synonymous way to extend functions on the prototype as described below:
var TeslaModelS = function() {
this.numWheels = 4;
this.manufacturer = 'Tesla';
this.make = 'Model S';
}
TeslaModelS.prototype = {
go: function() {
// Rotate wheels
},
stop: function() {
// Apply brake pads
}
}
Similar to Module pattern, the Prototype pattern also has a revealing variation. The Revealing Prototype Pattern provides encapsulation with public and private members since it returns an object literal.
Since we are returning an object, we will prefix the prototype object with a function. By extending our example above, we can choose what we want to expose in the current prototype to preserve their access levels:
var TeslaModelS = function() {
this.numWheels = 4;
this.manufacturer = 'Tesla';
this.make = 'Model S';
}
TeslaModelS.prototype = function() {
var go = function() {
// Rotate wheels
};
var stop = function() {
// Apply brake pads
};
return {
pressBrakePedal: stop,
pressGasPedal: go
}
}();
Note how the functions stop and go will be shielded from the returning object due to being outside of returned object’s scope. Since JavaScript natively supports prototypical inheritance, there is no need to rewrite underlying features.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
Every developer strives to write maintainable, readable, and reusable code. Code structuring becomes more important as applications become larger. Design patterns prove crucial to solving this challenge - providing an organization structure for common issues in a particular circumstance.
The design pattern below is only one of many useful patterns that can help you level up as a JavaScript developer. For the full set, see JavaScript Design Patterns.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!