if prototypes can't access private variables, what's the best way to "clean up" the code?
Hey guys, what i have now is this:
var Human=function(){
this._a=Math.random();
};
(function() {
var b开发者_运维百科efore_get = function(human) {
};
var before_set = function(human, v) {
};
Human.prototype={
get A(){
before_get(this);
return this._a;
},
set A(v){
before_set(this, v);
this._a=v;
}
};
})();
alert(new Human().A); // test
alert(new Human().A); // test
and all's good except that i do not wish to expose the variable _a to anywhere else except the prototype. Ok i've did some searching and realised that that's not possible so I was wondering do we usually leave it as such (i mean do we just leave those _a variables flying around or is there a better solution)?
There is no such thing as private in JavaScript, so this is not achievable. In general we do not have generic properties or setter/getters like other C#/Java have.
A pattern that can be used is closures instead of prototypes.
var Human = function() {
var a = Math.random();
var o = {};
Object.defineProperties(o, {
"A": {
"get": function() {
return a;
},
"set": function(val) {
a = val;
}
}
});
return o;
}
In general though you shouldnt write properties to the prototype. The prototype should contain methods.
The only way to clean up this._a
is as follows
var Human = (function() {
var Human=function(){
this._a=Math.random();
};
var before_get = function(human) {
};
var before_set = function(human, v) {
};
Human.prototype={
getA(){
before_get(this);
return this._a;
},
setA(v){
before_set(this, v);
this._a=v;
}
};
return function(args) {
var h = new Human(args);
return {
getA: h.getA.bind(h),
setA: h.setA.bind(h)
}
}
})();
Here is how you create the likes of a private/static variables using prototypal 'inheritance'. The trick is to define the prototype methods within the constructor (once). The price is getters/setters you have to execute. The profit is simplicity and a true prototypal solution (which after all is the real nature of the beast). And btw, here you create your 'getter/setter' only once, and it's there for all 999(999) instances you create from it.
function Human() {
var a = 'We are all Human',
o = {}
proto = Human.prototype;
if (!proto.A) {
//uncomment and create a few instances to see
//this is only executed once
//console.log('adding prototypes');
proto.A = function() {return a;};
proto.set = function(val) {a = val || a;};
proto.setName = function(val) {this.name = val || ''};
proto.getName = function(){
if (!this.name) {this.setName('no name yet');}
return this.name;};
}
}
var Pete = new Human,
Jean = new Human;
console.log(Pete.A()+':'+Jean.A());
//|=> We are all Human:We are all Human
Pete.set(Pete.A()+' except Jean'));
console.log(Pete.A()+':'+Jean.A());
//|=> We are all Human except Jean:We are all Human except Jean
Pete.setName('Hi, I am Pete. '+Pete.A());
Jean.setName('Hi, I am Jean. ' +Jean.A()+ '. Damn! thats me!');
console.log(Pete.name);
//|=> Hi, I am Pete. We are all Human except Jean
console.log(Jean.name);
//|=> Hi, I am Jean. We are all Human except Jean. Damn! thats me!
You have to realize that anyone can decide to assign something else to Human.prototype.A
. But if they do that outside the constructor, the closure, and therefore a
, is not available anymore.
精彩评论