Reputation: 59
The simplicity and flexibility of JavaScript's concept of an "object" (really a map) has always appealed to me. For that reason, I prefer to completely avoid the concept of "object prototypes" (and "classes" which are simply syntactic sugar for object prototypes) and opt for a factory pattern instead.
I came across this article, stating that object prototypes conserve memory in comparison to the factory pattern: https://medium.freecodecamp.org/class-vs-factory-function-exploring-the-way-forward-73258b6a8d15
"All methods will be created only once in the prototype object and shared by all instances"
Assume I have a web page which calls the following function lots of times to "instantiate" many AnglePointer objects:
var AnglePointer = function() {
var privateMembers = {};
privateMembers.angle = 0;
var self = {};
self.turn = function(degrees) {
privateMembers.angle += degrees;
while (privateMembers.angle > 359) {
privateMembers.angle -= 360;
}
while (privateMembers.angle < 0) {
privateMembers.angle += 360;
}
};
return self;
};
Can I improve the memory efficiency by introducing a "shared" object like the following?
var AnglePointer = (function() {
var sharedMembers = {};
sharedMembers.turn = function(self, privateMembers, degrees) {
privateMembers.angle += degrees;
while (privateMembers.angle > 359) {
privateMembers.angle -= 360;
}
while (privateMembers.angle < 0) {
privateMembers.angle += 360;
}
};
return function() {
var privateMembers = {};
privateMembers.angle = 0;
var self = {};
self.turn = function(degrees) {
shared.turn(self, privateMembers, degrees);
};
return self;
};
})();
In the second version, the implementation of the turn
function is inside the sharedMembers
object, leaving each "instance" of AnglePointer with just a small one-line function calling the shared function. Will this accomplish memory efficiency similar to that of an object prototype? Or will each instance's turn
function take up just as much memory as before despite being a one-line function? If the latter, how do object prototypes avoid this problem?
Upvotes: 0
Views: 368
Reputation: 138317
with just a small one-line function calling the shared function
That is based on the missbelief that a new function will be created for every object. That is wrong. All functions in your code are parsed just once and only exist once. What gets created on every creation is a new closure (the spec calls it EnvironmentRecord). If the function foes not access any outer variables, this closure can be optimized away making it way more memory efficient (and probably faster).
Therefore your "new pattern" makes things actually worse (but just a bit). The main problem stays:
self.turn = function(degrees) {
shared.turn(self, privateMembers, degrees);
};
That can't be optimized away, as the function uses variables from its parent's scope, and therefore a closure has to be created. Therefore there has to be a closure for every turn
method, and every object has to keep a reference to its own closured turn
.
Private members can be implemented quite accurately with Symbols:
const angle = Symbol.for("angle");
function AnglePointer() {
return {
[angle]: 0,
turn(degrees) {
this[angle] = (this[angle] + degrees) % 360;
},
};
}
Here the turn
can hopefully be shared as it does not access any outer variables.
Upvotes: 2