Skip to content Skip to sidebar Skip to footer

Pseudo-classical Inheritance With Privacy?

In JavaScript: The Good Parts, Crockford argues that one of the downsides of using the pseudo-classical pattern of inheritance is that it publicly exposes instance variables. For

Solution 1:

To answer your question; the only way to have intace specific private members is to have both the members and privileged functions (functions that can access them) in the same scope. This means they all have to be in the constructor body (var my private...this.myPrivileged=function(){ console.log (myPrivate...) or in a IIFE with a closure object keeping track of instances and their privates.

When returning an object private you already loose privacy because the calling code can mutate your private value. To prevent this you have to deep copy the value and return that.

To have privates on the prototype the privates will be shared. This because the instance is not known when declaring your prototype and private members.

This is because JavaScript doesn't have a private modifier and only simulates them through closures.

One pattern that can use prototype for instance specific protected variables is using Crockford's box example.

All protecteds are put in a box that can only be opened with a key, the key is available through closures to all prototype members defined in the IIFE.

Because the instance isn't known when creating prototype you have to invoke initProtecteds from the instance in order to create instance specific protected members.

Minimal code with an example protected instance member called medicalHistory is used in Animal.

functionmakeBox(key){
  var ret = {};
  return {
    get : function(pKey){
      if(pKey===key){
        return ret;
      }
      returnfalse;
    }
  }
};

varPerson = function(args){
  args = args || {};
  this.name = args.name || "Nameless Person";
  this.initProtecteds();
};

//using IIFE to define some members on Person.prototype//  these members and only these members have access to //  the passed object key (through closures)//  later the key is used to create a box for each instance//  all boxes use the same key so instances of same type//  can access each other's protected members and instances//  inheriting from Person can do so too, extending parent methods//  will be trickier, no example for that is given in this code
(function(key){
  //private shared membervar privateBehavior =  function(instance,args){
    //when you invoke this from public members you can pass//  the instance or use call/apply, when using call/apply//  you can refer to this as the current instance, when//  passing it as an argument then instance will //  be the current instanceconsole.log("private shared invoked");
  };
  //set default _protecteds to false so init knows//  it has not been initialised and needs to be shadowed//  with a boxPerson.prototype._protecteds=false;
  Person.prototype.getMedicalHistory = function(){
    //Maybe run some code that will check if you can access//  medical history, invoking a private methodprivateBehavior(this,{});
    var protectedObject  = this._protecteds.get(key);
    //if medicalHistory is an object the calling code//  can now mutate itreturn protectedObject.medicalHistory;
  };
  Person.prototype.hasSameDesease = function(person){
    //this Person instance should be able to see//  medical history of another Person instancereturn person._protecteds.get(key);
  };
  Person.prototype.getArr = function(){
    //Returns protecteds.get(key).arr so we can//  mutate it and see if protecteds are instance//  specificreturnthis._protecteds.get(key).arr;
  };
  Person.prototype.initProtecteds =  function(){
    //only create box if it hasn't been created yetif(this._protecteds!==false)
      return;
    //use the same key for all instance boxes, one instance//  can now open another instance's boxthis._protecteds=makeBox(key);
    //retreive the object held by the boxvar protectedObject  = this._protecteds.get(key);
    //add protected members by mutating the object held//   by the box
    protectedObject.medicalHistory = "something";    
    protectedObject.arr = [];
    //protectedObject is no longer needed
    protectedObject=null;
  };
}({}));
varAnimal = function(){
  this.initProtecteds();
};
(function(key){
  Animal.prototype._protecteds=false;
  Animal.prototype.initProtecteds =  function(){
    if(this._protecteds!==false)
      return;
    this._protecteds=makeBox(key);
    var protectedObject  = this._protecteds.get(key);
    protectedObject.medicalHistory = "something";    
  };
}({}));
varEmployee = function(args){
  //re use Person constructorPerson.call(this,args);
};
//set up prototype part of inheritanceEmployee.prototype = Object.create(Person.prototype);
//repair prototype.constructor to point to the right functionEmployee.prototype.constructor = Employee;

var ben = newPerson({name:"Ben"});
var nameless = newPerson();
console.log(ben.getMedicalHistory());//=something//key is in closure and all privileged methods are in that closure//  since {} !== {} you can't open the box unless you're in the closure//  or modify the code/set a breakpoint and set window.key=key in the closureconsole.log(ben._protecteds.get({}));//=false//One Person instance can access another instance's protecteds//  Objects that inherit from Person are sameconsole.log(ben.hasSameDesease(nameless));//=Object { medicalHistory="something"}var lady = newAnimal();
//An Animal type object cannot access a Person protected membersconsole.log(ben.hasSameDesease(lady));//=falsevar jon = newEmployee({name:"Jon"});
console.log(ben.hasSameDesease(jon));//=Object { medicalHistory="something"}//making sure that protecteds are instance specific
ben.getArr().push("pushed in ben");
console.log(jon.getArr());
console.log(nameless.getArr());
console.log(ben.getArr());

Solution 2:

This is interesting to consider.

To me (and I consider myself a student of js), it looks like only private member functions have access to the object's private variables. This is because it creates a closure around the var:

varBall = function(width, color) {
   var width = width;
   this.color = color;
   this.getWidth=function(){return width}
   this.specialWidthCalc=function(x){ width = width + x;}
}

So programmers can do:

  var redBall = newBall(5, "red");
  consoloe.log( redBall.getWidth() );

  redBall.specialWidthCalc(3);
  consoloe.log( redBall.getWidth() );

I am unable to create a prototype which has access to width.

Post a Comment for "Pseudo-classical Inheritance With Privacy?"