Reputation: 83
I create a Class using module pattern cuz I need some private members and functions. The problem is I can't create multiple instance for one module. If I create a new instance, it will replace all the instances I created before.
Here is the code.
var MyObj = (function() {
var myVar;
function MyObj(arg) {
myVar = arg;
}
MyObj.prototype.print = function() {
console.log(myVar);
};
return MyObj;
})();
var instance1 = new MyObj('instance1');
var instance2 = new MyObj('instance2');
instance1.print(); // instance2
instance2.print(); // instance2
Here is my questions: 1. Does this mean i can't create multiple instance for one Class if i want to use this pattern? 2. If i can't use this pattern, is there anyway else can have private in Class?
Upvotes: 1
Views: 1081
Reputation: 38
I don't know much about prototyping, but I think the use of the module pattern would result in something simpler, like this :
var MyObj = function(arg){
var myVar = arg;
var pub = {
print: function(){
console.log(myVar);
}
}
return pub;
};
var instance1 = MyObj('instance1');
var instance2 = MyObj('instance2');
instance1.print(); // instance1
instance2.print(); // instance2
Agreed, you don't have a 'Class' with this. But for me, the whole point of the module pattern is to have encapsulation without class-like hassles.
Upvotes: 0
Reputation: 1074228
You have at least four options:
The solution grape_mao outlined, which is Crockford's private pattern. The problem with it is that every instance gets its own getMyVar
function, they can't share them. This is the only way to get truly private properties in JavaScript right now.
The solution Tibos outlined, where myVar
isn't private anymore, but all of the prototype functions have access to it, you don't have new accessor functions for every instance.
That same solution as #2, prefixing the property name with a _
. Purely as a matter of convention, properties with names starting with _
are supposed to be off-limits to code outside the object. It's not remotely private, but it's cheap. I used to totally scoff at this approach, but someone pointed out to me that now that most modern languages have reflection, private members aren't really private even in Java and C# and such. :-)
Use the pattern that ES6 will use with private Name objects, replacing the private Name objects (since they don't exist yet!) with random strings. Your code doesn't worry about the actual name of the property, and other code can't reasonably guess it. Still only pseudo-private, but much more private than #2 or #3; not as much as #1. I outline how this works in this article. Basically it looks like this:
var MyObj = (function() {
var myVarName = new Name();
function MyObj(arg) {
this[myVarName] = arg;
}
MyObj.prototype.print = function() {
console.log(this[myVarName]);
};
return MyObj;
})();
var instance1 = new MyObj('instance1');
var instance2 = new MyObj('instance2');
instance1.print(); // instance2
instance2.print(); // instance2
...where Name
looks something like this:
var Name = function() {
var used = {};
function Name() {
var length, str;
do {
length = 5 + Math.floor(Math.random() * 10);
str = "_";
while (length--) {
str += String.fromCharCode(32 + Math.floor(95 * Math.random()));
}
}
while (used[str]);
used[str] = true;
return new String(str); // Since this is called via `new`, we have to return an object to override the default
}
return Name;
}();
Details in the article.
Upvotes: 3
Reputation: 27823
You have multiple instances of the MyObj
class, but you use myVar
as a static variable, so it is shared between instances.
This code should work properly:
var MyObj = (function() {
function MyObj(arg) {
this.myVar = arg;
}
MyObj.prototype.print = function() {
console.log(this.myVar);
};
return MyObj;
})();
var instance1 = new MyObj('instance1');
var instance2 = new MyObj('instance2');
instance1.print(); // instance1
instance2.print(); // instance2
Demo: http://jsbin.com/EPirAki/1/edit
Take a look at this blog post (curtesy of T.J. Crowder - see comments) that explains how you can use random to get near-private variables: http://blog.niftysnippets.org/2013/05/private-properties-in-es6-and-es3-and.html
Upvotes: 2
Reputation: 2259
Prototype functions can't directly access private variables.
var MyObj = (function() {
var abc = "shared by all MyObj"; // this variable is shared through all MyObj instances created and doesn't belong to MyObj
function MyObj(arg) {
var privateVar = arg;
this.getPrivateVar = function(){ return privateVar; }
this.myVar = arg;
}
MyObj.prototype.print = function() {
//console.log(privateVar); // cannot access variable
console.log(this.getPrivateVar()); // using a getter function you can access that private variable and limit its mutation
console.log(this.myVar);
};
return MyObj;
})();
var instance1 = new MyObj('instance1');
var instance2 = new MyObj('instance2');
instance1.print(); // instance2
instance2.print(); // instance2
Upvotes: 0
Reputation: 1153
You'll need a privilege function who has access to the variable.
var MyObj = (function() {
function MyObj(arg) {
this.getMyVar = function(){
return arg;
};
}
MyObj.prototype.print = function() {
console.log(this.getMyVar());
};
return MyObj;
})();
var instance1 = new MyObj('instance1');
var instance2 = new MyObj('instance2');
instance1.print(); // instance2
instance2.print(); // instance2
Upvotes: 1