回答你的问题;拥有特定私有成员的唯一方法是让成员和特权函数(可以访问它们的函数)在同一范围内。这意味着它们都必须在构造函数主体中(var my private...this.myPrivileged=function(){ console.log (myPrivate...) 或在具有闭包对象的 IIFE 中,跟踪实例及其私有.
当返回一个私有对象时,你已经失去了隐私,因为调用代码可以改变你的私有值。为了防止这种情况,您必须深度复制该值并返回该值。
要在原型上拥有私有数据,私有数据将被共享。这是因为在声明您的原型和私有成员时不知道该实例。
这是因为 JavaScript 没有私有修饰符,只能通过闭包来模拟它们。
可以使用原型作为实例特定受保护变量的一种模式是使用 Crockford 的盒子示例。
所有受保护的物品都放在一个只能用钥匙打开的盒子里,钥匙可以通过对 IIFE 中定义的所有原型成员的封闭来获得。
因为在创建原型时实例是未知的,所以您必须从实例调用 initProtecteds 以创建实例特定的受保护成员。
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());