Javascript when to use prototypes
Prototypes are an optimisation.
A great example of using them well is the jQuery library. Every time you obtain a jQuery object by using $('.someClass')
, that object has dozens of "methods". The library could achieve that by returning an object:
return {
show: function() { ... },
hide: function() { ... },
css: function() { ... },
animate: function() { ... },
// etc...
};
But that would mean that every jQuery object in memory would have dozens of named slots containing the same methods, over and over.Instead, those methods are defined on a prototype and all jQuery objects "inherit" that prototype so as to gain all those methods at very little runtime cost.
One vitally important part of how jQuery gets it right is that this is hidden from the programmer. It's treated purely an optimisation, not as something that you have to worry about when using the library.
The problem with JavaScript is that naked constructor functions require the caller to remember to prefix them with new
or otherwise they typically don't work. There is no good reason for this. jQuery gets it right by hiding that nonsense behind an ordinary function, $
, so you don't have to care how the objects are implemented.
So that you can conveniently create an object with a specified prototype, ECMAScript 5 includes a standard function Object.create
. A greatly simplified version of it would look like this:
Object.create = function(prototype) {
var Type = function () {};
Type.prototype = prototype;
return new Type();
};
It just takes care of the pain of writing a constructor function and then calling it with new
.When would you avoid prototypes?
A useful comparison is with popular OO languages such as Java and C#. These support two kinds of inheritance:
- interface inheritance, where you
implement
aninterface
such that the class provides its own unique implementation for every member of the interface. - implementation inheritance, where you
extend
aclass
that provides default implementations of some methods.
However, if you're in a situation where you would have used interfaces in C# or Java, then you don't need any particular language feature in JavaScript. There is no need to explicitly declare something that represents the interface, and no need to mark objects as "implementing" that interface:
var duck = {
quack: function() { ... }
};
duck.quack(); // we're satisfied it's a duck!
In other words, if each "type" of object has its own definitions of the "methods", then there is no value in inheriting from a prototype. After that, it depends on how many instances you allocate of each type. But in many modular designs, there is only one instance of a given type.And in fact, it has been suggested by many people that implementation inheritance is evil. That is, if there are some common operations for a type, then maybe it's clearer if they are not put into a base/super class, but are instead just exposed as ordinary functions in some module, to which you pass the object(s) you want them to operate on.
What’s the purpose of prototype?
Using the prototype makes faster object creation since properties/methods on the prototype don't have to be re-created each time a new object is created.
When you do this:
function animal() {
this.name = 'rover'
this.set_name = function (name) {
this.name = name
}
}
The set_name
method is created every time you create an animal. But when you do thisanimal.prototype.set_name = function (name) {
this.name = name
}
The method does not have to be re-created each time; it exists in one place in the prototype. So when you call someAnimal.set_name("Ubu");
the this
context will be set to someAnimal
and (the one and only) set_name
method will be called.There is one advantage to using the first syntax though: methods created in this manner will have access to private data:
function animal() {
var privateData = 'foo'
this.name = 'rover'
this.set_name = function (name) {
this.name = name
alert(privateData) //will alert 'foo'
}
}
Douglas Crockford calls methods created like this "privileged" for that reason: they have access to both public and private data. JavaScript: When to use a Class vs. a prototype?
To answer your question simply, there is no real difference.So, what is the difference between using a class vs. a prototype like below and when do you use either approach?
Straight from the MDN web docs definition:
JavaScript classes, introduced in ECMAScript 2015, are primarily syntactical sugar over JavaScript's existing prototype-based inheritance.
Should I use prototype or not?
This is exactly the situation for using prototype. I see two main benefits for doing so:
- Functions are not created multiple times. If you define the functions inside the constructor, a new anonymous function is being created for each function you define, every time the constructor is called. Prototypes are static objects, and each instance of Vector3D will simply reference the prototype functions.
- The prototype is a single object that can be easily manipulated. This affords great flexibility; unfortunately I'm only able to provide a few examples of what this can offer:
- If you wanted to create a child class, for example Vector3DSpecial, you can simply clone
Vector3D.prototype
and assign this toVector3DSpecial.prototype
. While you can also do this using constructors byVector3DSpecial.prototype = new Vector3D();
, constructors may contain side-effects which will get executed in that simple prototype assignment, and therefore should be avoided. With prototypes, you may even choose only particular functions in the prototype to be copied over to the new class. - Adding methods to
Vector3D
is simply a matter of adding properties to the prototype, and allows your code to be more easily split / organised into multiple files, or to allow for adding methods in other parts of the code dynamically. Sure, you can do a combination of adding methods in the constructor and via the prototype, but that is inconsistent and is likely to lead to more complexity further down the track.
- If you wanted to create a child class, for example Vector3DSpecial, you can simply clone
When should I use prototype in JavaScript
Simplest example:
function Foo() {
this.bar = function() {
return 42;
}
}
Now you can create as many instances of Foo
as you want and call bar()
:var a = new Foo();
var b = new Foo();
Even though both object have bar()
method which is exactly the same in both cases, these are distinct methods. In fact, each new Foo
object will have a new copy of this method. On the other hand:
function Foo() {}
Foo.prototype.bar = function() {
return 42;
}
has the same end result but the function is stored only once in object prototype
rather than in an object itself. This may be a deal breaker if you create tons of Foo
instances and want to save some memory. What is the use of prototype in Node js?
In short, prototype
is used to build the interface (and implementation) of your custom-build objects in JavaScript.
As said Blender in the comment, it's how you do real OOP in JavaScript.
Do we still need prototype in ES6 to have one copy of a method shared across all class instances?
ES6 classes are syntactic sugar for established inheritance pattern that have been used in ES5.
ES6 classes use prototype methods by design. A method is shared among instances, so it's reasonable to define it once on prototype
object and prototypically inherit it in instances. Prototypes are consistently optimized in modern engines and show performance benefits in some cases, so they can be preferred where appropriate.
Memory footprint can be reduced by reusing a function. This isn't a 'modern' way, just a way to address the issue:My question was more about using a more modern way to achieve what I wanted, i.e. not having copies of methods.
function function f(){}
function FC() {
this.v = 42;
this.f = f;
};
A 'modern' way is to use prototype members.FC
function is not a direct counterpart to X
class because the former assigns f
on instance, not constructor prototype. A direct counterpart (with the exception of f
descriptor, which is also non-enumerable in ES6 class) would be:
function FC() {
this.v = 42;
};
FC.prototype.f = function(){};
class X{
constructor(){
this.v = 'bar';
}
f(){}
}
// typeof X.prototype.f === 'function'
The reason why this style wasn't used consistently in ES5 is because this.f
takes less characters to type and may be more readable than FC.prototype.f
, while a developer may be unaware of the benefits and quirks of prototype
.The promotion of prototype members (methods and getters/setters) is one of few problems that class
syntactic sugar addresses.
Related Topics
Why Are Es6 Classes Not Hoisted
Cancel/Kill Window.Settimeout() Before It Happens
If (Key in Object) or If(Object.Hasownproperty(Key)
What Is Event Pooling in React
JavaScript Displaying a Float to 2 Decimal Places
Differencebetween React Native and React
Decompress Gzip and Zlib String in JavaScript
Nodejs Timeout a Promise If Failed to Complete in Time
How to Know When All Promises Are Resolved in a Dynamic "Iterable" Parameter
How to Set Node_Env to Production/Development in Os X
Uncaught Typeerror: Cannot Use 'In' Operator to Search for 'Length' In
What Are Some Empirical Technical Reasons Not to Use Jquery
How to Sum the Values of a JavaScript Object
Unexpected Token Illegal in Webkit
What Exactly Can Cause an "Hierarchy_Request_Err: Dom Exception 3"-Error
How to Randomly Generate HTML Hex Color Codes Using JavaScript