隐私的伪古典inheritance?

JavaScript中:好的部分 ,Crockford认为,使用伪古典模式的inheritance的缺点之一是它公开暴露实例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 

现在,如果我想要球的宽度是私人的呢?

以下是我所尝试的:

 var Ball = function(width, color) { this.getWidth = function() { return width; } this.color = color; } var redBall = new Ball(5, "red"); 

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

关于什么 …

 var Ball = function(width, color) { return { getWidth: function() { return width; }, color: color } } var redBall = new Ball(5, "red"); 

问题是原型方法不再有权访问实例variables。 它也更接近inheritance的function模式,但更多的间接使用new运算符。

那么如何使用伪古典inheritance模式来实现隐私呢? 这甚至有可能吗?

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

当返回一个对象的私人,你已经松动隐私,因为调用代码可以改变你的私人价值。 为了防止这种情况,你必须深入复制这个值并返回。

为了在原型上拥有私人物,私人物将被共享。 这是因为实例在声明原型和私有成员时是不知道的。

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

一个可以使用原型的特定保护variables的模式是使用Crockford的框例子。

所有的受保护者都被放在一个只能用钥匙打开的盒子里,钥匙可以通过closures所有在IIFE中定义的原型成员。

由于在创build原型时不知道实例,因此必须从实例中调用initProtecteds以创build实例特定的受保护成员。

在Animal中使用一个名为medicalHistory的示例保护实例成员的最小代码。

 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()); 

这是有趣的考虑。

对我来说(我认为自己是js的学生),看起来只有私有成员函数才能访问该对象的私有variables。 这是因为它创build了一个关于var的闭包:

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

所以程序员可以这样做:

  var redBall = new Ball(5, "red"); consoloe.log( redBall.getWidth() ); redBall.specialWidthCalc(3); consoloe.log( redBall.getWidth() ); 

我无法创build一个可以访问宽度的原型。