隐私的伪经典继承? [英] Pseudo-classical inheritance with privacy?

查看:162
本文介绍了隐私的伪经典继承?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

JavaScript:好的部分中,Crockford认为使用伪经典继承模式的一个缺点是它公开暴露了实例变量。

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.

例如:

var Ball = function(width, color) {
  this.width = width;
  this.color = color;
}

var redBall = new Ball(5, "red");
redBall.width = 12; // Changes width to 12

现在,如果我希望球的宽度是私有的怎么办?

Now, what if I want the width of the ball to be private?

以下是我的尝试:

var Ball = function(width, color) {
  this.getWidth = function() { return width; }
  this.color = color;
}

var redBall = new Ball(5, "red");

问题是我们仍然可以改变 this.getWidth 并且可能存在依赖于它的原型方法。

Problem with that is we can still change this.getWidth and there may be prototype methods that rely on it.

怎么样......

var Ball = function(width, color) {
  return {
    getWidth: function() { return width; },
    color: color
  }
}

var redBall = new Ball(5, "red");

问题在于原型方法不再能够访问实例变量。它也更接近继承的功能模式,但使用 new 运算符的间接更多。

Problem with that is that the prototype methods no longer have access to the instance variables. It's also closer to the functional pattern of inheritance, but with more indirection using the new operator.

那么如何使用伪经典继承模式实现隐私?这甚至可能吗?

So how do I achieve privacy using the pseudo-classical inheritance pattern? Is this even possible?

推荐答案

回答你的问题;嵌入特定私有成员的唯一方法是在同一范围内同时拥有成员和特权函数(可以访问它们的函数)。这意味着它们都必须位于构造函数体中(var我的私有... this.myPrivileged = function(){console.log(myPrivate ...)或带有闭包对象的IIFE跟踪实例和他们的私有

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.

这是因为JavaScript没有私有修饰符,只能通过闭包来模拟它们。

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

一种可以使用原型作为特定受保护变量的模式正在使用Crockford的方框示例。

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

所有受保护物都放在一个只能用钥匙打开的盒子里面key可通过闭包到IIFE中定义的所有原型成员。

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.

因为创建原型时实例未知,所以必须从实例调用initProtecteds才能创建特定于实例的受保护成员。

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.

在Animal中使用带有示例受保护实例成员的最小代码,名为medicalHistory。

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

function makeBox(key){
  var ret = {};
  return {
    get : function(pKey){
      if(pKey===key){
        return ret;
      }
      return false;
    }
  }
};

var Person = 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 member
  var 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 instance
    console.log("private shared invoked");
  };
  //set default _protecteds to false so init knows
  //  it has not been initialised and needs to be shadowed
  //  with a box
  Person.prototype._protecteds=false;
  Person.prototype.getMedicalHistory = function(){
    //Maybe run some code that will check if you can access
    //  medical history, invoking a private method
    privateBehavior(this,{});
    var protectedObject  = this._protecteds.get(key);
    //if medicalHistory is an object the calling code
    //  can now mutate it
    return protectedObject.medicalHistory;
  };
  Person.prototype.hasSameDesease = function(person){
    //this Person instance should be able to see
    //  medical history of another Person instance
    return person._protecteds.get(key);
  };
  Person.prototype.getArr = function(){
    //Returns protecteds.get(key).arr so we can
    //  mutate it and see if protecteds are instance
    //  specific
    return this._protecteds.get(key).arr;
  };
  Person.prototype.initProtecteds =  function(){
    //only create box if it hasn't been created yet
    if(this._protecteds!==false)
      return;
    //use the same key for all instance boxes, one instance
    //  can now open another instance's box
    this._protecteds=makeBox(key);
    //retreive the object held by the box
    var 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;
  };
}({}));
var Animal = 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";    
  };
}({}));
var Employee = function(args){
  //re use Person constructor
  Person.call(this,args);
};
//set up prototype part of inheritance
Employee.prototype = Object.create(Person.prototype);
//repair prototype.constructor to point to the right function
Employee.prototype.constructor = Employee;

var ben = new Person({name:"Ben"});
var nameless = new Person();
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 closure
console.log(ben._protecteds.get({}));//=false
//One Person instance can access another instance's protecteds
//  Objects that inherit from Person are same
console.log(ben.hasSameDesease(nameless));//=Object { medicalHistory="something"}
var lady = new Animal();
//An Animal type object cannot access a Person protected members
console.log(ben.hasSameDesease(lady));//=false
var jon = new Employee({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());

这篇关于隐私的伪经典继承?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆