I completely understand why it's better to use the prototype instead of the constructor to define a class method, (i.e. Use of 'prototype' vs. 'this' in JavaScript?) However, I recently came across a HashMap class that defines the count
property in the prototype and the map
property in the constructor:
js_cols.HashMap = function(opt_map, var_args) {
/**
* Underlying JS object used to implement the map.
* @type {!Object}
* @private
*/
this.map_ = {};
/...
}
/**
* The number of key value pairs in the map.
* @private
* @type {number}
*/
js_cols.HashMap.prototype.count_ = 0;
Are there advantages of declaring an instance property like count
in the prototype instead of saying this.count_ = 0;
in the constructor? And if so, why not also js_cols.HashMap.prototype.map_ = {};
?
Edit: A similar question was asked, Why declare properties on the prototype for instance variables in JavaScript, and "default values" was raised as a use case, but it was not explained why this is more desirable than just defining the default value in the constructor.
Instance properties are those properties that are defined inside any class and require an instance that is created with the help of the class name itself. Without creating the instance of the class, we may not be able to access these properties which are defined inside the class.
So what's the difference between constructor and prototype? A short answer is that the constructor is a function that is used to create an object, while the prototype is an object that contains properties and methods that are inherited by objects created from a constructor.
constructor. The constructor property returns a reference to the Object constructor function that created the instance object. Note that the value of this property is a reference to the function itself, not a string containing the function's name.
prototype, constructor property. Every function has the "prototype" property even if we don't supply it. The default "prototype" is an object with the only property constructor that points back to the function itself. We can use constructor property to create a new object using the same constructor as the existing one.
I don't think the HashMap
class is the best example of the benefits of declaring an instance property in the prototype. Consider instead a Response
class:
function Response() {
this.headers = {};
}
Response.prototype.statusCode = 200;
All instances of Response
will share the statusCode
of 200
— literally, the same number in memory will be shared across all instances. This makes sense if you expect your server to respond with status code 200 most of the time. Those Requests
that need different status codes can overwrite their default statusCode
, which creates a new number in memory.
I.e. If you have 10,000 concurrent requests, and 5 of them are 404's, you got away with only having 6 numbers in memory to represent all 10,000 statusCodes
.
In summation, it might be worth it to use prototype if you expect a lot of instances to share the same default value most of the time. Otherwise, you can chalk it up to coding style. (Obviously for static properties, always use prototype.)
Note see Lucas's answer for why a property that's an object (e.g. map
or headers
) can't be in the prototype: all instances would be sharing the same reference, thus any update to that reference would update all instances.
It depends on how it is used, are you sure count_
doesn't define the number of hash buckets there are, rather than the exact count of how many items are in the hash? Defining variables in the prototype is good if you expect the value to remain constant and global for all instances of the class, since only memory for one variable is being used regardless of how many class instances you make.
It works for count_
, but it wouldn't work for map_
.
count_
is an integer value, while map_
is an object reference. If a HashMap
instance updates count_
, it will essentially create a count_
property on its own instance.
But, if it inserts something to the map_
, as all instances share the same map_
reference, all instances would end up with the same values in the map. This wouldn't work, and that's why every instance get a different map_
reference in its constructor.
As for the count_
property, it's declared in the prototype just as a default. It would be the same if it was instantiated in the constructor. I guess it's just a matter of coding style.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With