I have been re-factoring someone else's JavaScript code.
BEFORE:
function SomeObj(flag) {
var _private = true;
this.flag = (flag) ? true : false;
this.version="1.1 (prototype)";
if (!this._someProperty) this._init();
// leading underscore hints at what should be a 'private' to me
this.reset(); // assumes reset has been added...
}
SomeObj.prototype.reset = function() {
/* perform some actions */
}
/* UPDATE */
SomeObj.prototype.getPrivate = function() {
return _private; // will return undefined
}
/* ...several other functions appended via `prototype`...*/
AFTER:
var SomeObj = function (flag) {
var _private = true;
this.flag = (flag) ? true : false;
this.version = "2.0 (constructor)";
this.reset = function () {
/* perform some actions */
};
/* UPDATE */
this.getPrivate = function() {
return _private; // will return true
}
/* other functions and function calls here */
}
For me the first example looks difficult to read, especially in a larger context. Adding methods like reset
on like this, using the prototype
property, seems much less controlled as it can presumably happen anywhere in the script. My refactored code (the second example above) looks much neater to me and is therefore easier to read because it's self-contained. I've gained some privacy with the variable declarations but I've lost the possibilities the prototype chain.
...
QUESTIONS:
Firstly, I'm interested to know what else I have lost by foregoing
prototype
, or if there are larger implications to the loss of the prototype chain. This article is 6 years old but claims that using theprototype
property is much more efficient on a large scale than closure patterns.Both the examples above would still be instantiated by a
new
operator; they are both 'classical'-ish constructors. Eventually I'd even like to move away from this into a model where all the properties and functions are declared asvar
s and I have one method which I expose that's capable of returning an object opening up all the properties and methods I need, which have privileges (by virtue of closure) to those that are private. Something like this:var SomeObj = (function () { /* all the stuff mentioned above, declared as 'private' `var`s */ /* UPDATE */ var getPrivate = function () { return private; } var expose = function (flag) { // just returns `flag` for now // but could expose other properties return { flag: flag || false, // flag from argument, or default value getPrivate: getPrivate } }; return { expose: expose } })(); // IIFE // instead of having to write `var whatever = new SomeObj(true);` use... var whatever = SomeObj.expose();
There are a few answers on StackOverflow addressing the 'prototype vs. closure' question (here and here, for example). But, as with the
prototype
property, I'm interested in what a move towards this and away from thenew
operator means for the efficiency of my code and for any loss of possibility (e.g.instanceof
is lost). If I'm not going to be using prototypal inheritance anyway, do I actually lose anything in foregoing thenew
operator?A looser question if I'm permitted, given that I'm asking for specifics above: if
prototype
andnew
really are the most efficient way to go, with more advantages (whatever you think they might be) than closure, are there any guidelines or design patterns for writing them in a neater fashion?
...
UPDATE:
Note that expose
returns a new object each time, so this is where the instantiation happens. As I understand this, where that object refers to methods declared in the SomeObj
closure, they are the same methods across all objects (unless overwritten). In the case of the flag
variable (which I've now corrected), this can be inherited from the argument of expose
, have a default value, or again refer back to a encapsulated pre-existing method or property. So there are instances of objects being produced and there is some inheritance (plus polymorphism?) going on here.
So to repeat question 2: If I'm not going to be using prototypal inheritance anyway, do I actually lose anything in foregoing the new
operator?
Many thanks for answers so far, which have helped to clarify my question.