开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜