What exactly is different about these 2 objects, a
created using a constructor, b
using a closure?
Is the property __proto__
useful for anything that cannot be achieved by using a closure? Am I supposed to use these techniques in different situations? Is there a difference in memory usage?
(jsFiddle)
window.MODULE = {};
MODULE.constructor = function(){
this.publicVariable = 10;
};
MODULE.constructor.prototype.publicMethod = function(){
return this.publicVariable;
};
//-------------------------------//
MODULE.closure = (function(){
var publicMethod = function(){
return this.publicVariable;
};
return function(){
var obj = {};
obj.publicVariable = 10;
obj.publicMethod = publicMethod;
return obj;
};
}());
//-------------------------------//
var a = new MODULE.constructor();
console.log("constructor", a.publicMethod(), a)
var b = MODULE.closure();
console.log("closure", b.publicMethod(), b)
Also see a more plicated jsFiddle parison with some private and static properties - both techniques work the same as far as I can tell...
What exactly is different about these 2 objects, a
created using a constructor, b
using a closure?
Is the property __proto__
useful for anything that cannot be achieved by using a closure? Am I supposed to use these techniques in different situations? Is there a difference in memory usage?
(jsFiddle)
window.MODULE = {};
MODULE.constructor = function(){
this.publicVariable = 10;
};
MODULE.constructor.prototype.publicMethod = function(){
return this.publicVariable;
};
//-------------------------------//
MODULE.closure = (function(){
var publicMethod = function(){
return this.publicVariable;
};
return function(){
var obj = {};
obj.publicVariable = 10;
obj.publicMethod = publicMethod;
return obj;
};
}());
//-------------------------------//
var a = new MODULE.constructor();
console.log("constructor", a.publicMethod(), a)
var b = MODULE.closure();
console.log("closure", b.publicMethod(), b)
Also see a more plicated jsFiddle parison with some private and static properties - both techniques work the same as far as I can tell...
Share Improve this question edited Oct 7, 2013 at 12:31 Aprillion asked Sep 19, 2013 at 18:11 AprillionAprillion 22.3k6 gold badges58 silver badges91 bronze badges 5-
note there is only 1 instance of
publicMethod
in both cases, so prototype version should not consume less memory than closure in this particular case – Aprillion Commented Oct 7, 2013 at 12:50 - 1 You still need extra fields on the object tables to point to the shared public method and you won't be able to share any private methods you create. That said, for the vast majority of Javascript programs the the coding style differences will be more important than performance. Finally, you are still free to mix both styles if you really want to but private methods must be implemented with closures and you wont be able to monkey match them. – hugomg Commented Oct 7, 2013 at 12:59
- @missingno you can share private methods using prototypical inheritance? – Aprillion Commented Oct 7, 2013 at 13:07
- you can't share private methods because private methods are closures and each closure needs to close over a different set of variables. The methods probably share their inner "code pointer" but since JS functions are mutables the function objects themselves cannot be shared (and as far as I know, most implementations dont optimize this). That said, the performance shouldnt matter unless you are doing something really performance sensitive (in which case you are going to need to worry about how different implementations optimize your code) – hugomg Commented Oct 7, 2013 at 13:42
- 1 @deathApril You can have "private" (called privileged) methods by having a function return a prototype that contains closures. – HMR Commented Oct 7, 2013 at 15:45
3 Answers
Reset to default 6Roughly, the main advantages of prototypal inheritance (your "constructor" method) are makes it easier to do subclasses and monkeypatching (adding methods to an existing class) while closures are nice if you want private instance variables and methods ("protected methods" are still hard to do with either method) or prefer lexical scoping instead of dynamic scoping with "this" (useful if someone does setTimeout(obj.method, 1000)
)
As for performance, prototypal inheritance can be a bit more efficient because implementations are tuned to it but it really shouldn't matter unless you instantiate lots of objects from that class.
Private variable example:
var counter = function(){
var count = 0; //private variable
var increment = function(){ // private method
count ++;
};
return { //public interface
next: function(){
increment();
return count;
},
}
}
var c = counter();
console.log(c.next());
console.log(c.next());
If we skip the advantages of OOP approach, difference between a
and b
is that b
has own method publicMethod
, when a
inherits this method from it's prototype:
a.hasOwnProperty('publicMethod'); // false
b.hasOwnProperty('publicMethod'); // true
Note, that __proto__
property is non-standard and not supported in IE < 11. Alternatively you may use ES5 feature Object.getPrototypeOf(a)
.
Also note naming conventions it JavaScript1:
UPPER_CASE
is used for constants, when globals usually usePascalCase
, so yourMODULE
should beModule
;- constructors use
PascaleCase
too, so yourMODULE.constructor
should beModule.Constructor
.
More on prototype, inheritance, overriding and calling super here: https://stackoverflow./a/16063711/1641941
MODULE={};
MODULE.constructor = function(){
this.publicVariable = 10;
};
MODULE.constructor.prototype=(function(){
var privateMethod=function(){
console.log("I'm private");
};
return {
publicMethod : function(){
//going to call "private" method
privateMethod();
return this.publicVariable;
}
};
}());
var c = new MODULE.constructor();
c.publicMethod();
To have instance specific "private" member values you have to give up prototype because you have to define all functions accessing these values in the constructor function body instead of on the prototype. I personally think it's silly to forcefully implement something that is not supported by JavaScript (private instance specific variables) and by doing so giving up something that is supported by JavaScript (prototype).
By supported I mean that JS engines will optimise your code for it.