I get the basics of the Module Pattern and its use of a closure to allow for private members, BUT I can't quite swallow why the below code does what it does:
var Calculator = function() {
var priv = 0;
return {
changePriv: function() { priv++;},
printPriv: function() { console.log(priv);}
}
}
var myCalc = Calculator();
myCalc.printPriv();
myCalc.changePriv();
myCalc.printPriv();
var myOtherCalc = Calculator();
myCalc.printPriv();
The console output is
0
1
1
So purposefully omitting the new
keyword here, the first call sets myCalc
to a Calculator object. It starts out with a priv
value of 0, has that incremented, and then prints out its new priv
value of 1.
But a) WHY does the next call to Calculator()
end up returning a reference to the SAME object (as evidenced by the second '1')? I know I can use new
here and avoid that, but don't get why I have to. Isn't this function using object literal syntax to essentially create a new object and then return it?
b) Since it does seem to be using the same function stack space (is that even the right way to think of it in JS?), why doesn't it zero out the priv
variable in the process before returning the reference to the same object?
EDIT: Corrected sloppy/stupid mistake (thanks scessor), which DOES now output a new/distinct calculator object even without use of the new
keyword. So that clears up a) and b). My resulting question would have been "Does it matter whether I use new
or not in the invocation of a module-pattern constructor. The answer is, I guess it doesn't matter(?). (Joseph: see / ...the instanceof operator simply doesn't work with the module pattern either way.)
I get the basics of the Module Pattern and its use of a closure to allow for private members, BUT I can't quite swallow why the below code does what it does:
var Calculator = function() {
var priv = 0;
return {
changePriv: function() { priv++;},
printPriv: function() { console.log(priv);}
}
}
var myCalc = Calculator();
myCalc.printPriv();
myCalc.changePriv();
myCalc.printPriv();
var myOtherCalc = Calculator();
myCalc.printPriv();
The console output is
0
1
1
So purposefully omitting the new
keyword here, the first call sets myCalc
to a Calculator object. It starts out with a priv
value of 0, has that incremented, and then prints out its new priv
value of 1.
But a) WHY does the next call to Calculator()
end up returning a reference to the SAME object (as evidenced by the second '1')? I know I can use new
here and avoid that, but don't get why I have to. Isn't this function using object literal syntax to essentially create a new object and then return it?
b) Since it does seem to be using the same function stack space (is that even the right way to think of it in JS?), why doesn't it zero out the priv
variable in the process before returning the reference to the same object?
EDIT: Corrected sloppy/stupid mistake (thanks scessor), which DOES now output a new/distinct calculator object even without use of the new
keyword. So that clears up a) and b). My resulting question would have been "Does it matter whether I use new
or not in the invocation of a module-pattern constructor. The answer is, I guess it doesn't matter(?). (Joseph: see http://jsfiddle/MvMvy/5/ ...the instanceof operator simply doesn't work with the module pattern either way.)
-
2
By convention, functions starting with a capital letter are reserved for constructors (i.e. functions that are supposed to be called with
new
). TheCalculator
function explicitly returns an object so calling it withnew
doesn't make any difference to what it returns. – RobG Commented Apr 18, 2012 at 6:01 - Thanks RobG. That's exactly what I was hoping to get confirmation on. – user718147 Commented Apr 18, 2012 at 19:33
3 Answers
Reset to default 9You don't output the other calculator myOtherCalc
: if you want to pare them, replace the third myCalc.printPriv();
with:
myOtherCalc.printPriv();
Then the output is:
0
1
0
You don't need to use new
in your case.
Normally, if you use new
, you expect that what you get is an instance of that constructor you called. In your case, it won't because you manually returned an object. It would make no sense and will cause problems later of you confuse the usage. Soon you might be "instance testing" your objects, and will run into this "mismatch".
and you got a typo in your code:
var myCalc = Calculator(); //create calculator
myCalc.printPriv(); //"myCalc" private is 0
myCalc.changePriv(); //increment
myCalc.printPriv(); //"myCalc" private is 1
var myOtherCalc = Calculator(); //another calculator
myCalc.printPriv(); ///but you printed "myCalc" again
There's nothing to do with the "new" Operator... Here you get a well explained topic about proto/constructor : http://en.wikibooks/wiki/JavaScript/Access_Control
However it's a nonsense example, you can do this, so you can access priv via getter and setter methods only :
function Calculator2() {
var priv = 0;
this.public = 0;
this.getPriv = function(){
return priv;
}
this.setPriv = function(val){
priv = val;
}
}
Calculator2.prototype.changePriv = function(){
this.setPriv(this.getPriv()+1);
}
Calculator2.prototype.printPriv = function(){
console.log("priv = " + this.getPriv());
}
Calculator2.prototype.changePublic = function(){
this.public++;
}
Calculator2.prototype.printPublic = function(){
console.log(this.public);
}
In this case var priv is always accessible via a getter and a setter method,
In the next example you have a private var className and another public var __className :
<div id = "outputDiv" style="width:600px;height:400px;border:solid 1px #000"></div>
<script type="text/javascript">
//<![CDATA[
//script : var SomeClass = function(className) {
var __className__ = className;
this.__className__ = "\"public default className\"";
var someString = new String("");
this.setScopeText = function() { // void
someString = "A new instance of \"private [__classname__] : " +
__className__ + "\"" +
" has been created. Refering to [__className__]<br />" +
"A new instance of " +
this.__className__ +
" has been created. Refering to [this.__className__]";
return someString;
};
this.getScopeText= function (){
return someString;
}
this.setOutput = function(elementId, someString){
var outputPane = this.getSomePane(elementId);
outputPane.innerHTML += "<p>" + someString + "</p>";
}
this.getSomePane = function(elementId){
var outputP = document.getElementById(elementId);
return outputP;
}
}
SomeClass.prototype.changeClassNameVariable = function( str ){
this.__className__ = str;
}
// end declaration.
//tests :
var sc = new SomeClass("foo");
sc.setOutput("outputDiv",sc.__className__);
sc.setOutput("outputDiv",sc.setScopeText());
sc.setOutput("outputDiv",sc.getSomePane("outputDiv"));
sc.__className__ = "\"Some name\"";
sc.setOutput("outputDiv",sc.__className__);
sc.setOutput("outputDiv",sc.setScopeText());
sc.changeClassNameVariable("bar");
sc.setOutput("outputDiv",sc.__className__);
sc.setOutput("outputDiv",sc.setScopeText());
// ends javascript and CDATA section
//]]>
</script>
Output in "div:outputDiv" :
"public default className"
A new instance of "private [classname] : foo" has been created. Refering to [className] A new instance of "public default className" has been created. Refering to [this.className]
[object HTMLDivElement]
"Some name"
A new instance of "private [classname] : foo" has been created. Refering to [className] A new instance of "Some name" has been created. Refering to [this.className]
bar
A new instance of "private [classname] : foo" has been created. Refering to [className] A new instance of bar has been created. Refering to [this.className]
-> className declared in constructor never changes! -> this.className or SomeClass.prototype.className is public and may be changed.
I hope this may help to understand the chain and my ment more clearly...