如何在JavaScript中创建受保护的对象属性 有一个JavaScript模式,模仿“保护”对象属性,如C++语言?
基本上,我想创建一个对象A,它有许多“受保护”的对象属性,这些属性只能从对象A的原型定义的方法中访问,也就是说,不能从A的非原型方法公开访问 例如,理想情况是:如何在JavaScript中创建受保护的对象属性 有一个JavaScript模式,模仿“保护”对象属性,如C++语言?,javascript,prototype-programming,Javascript,Prototype Programming,基本上,我想创建一个对象A,它有许多“受保护”的对象属性,这些属性只能从对象A的原型定义的方法中访问,也就是说,不能从A的非原型方法公开访问 例如,理想情况是: function A(){ var prop1 = 1; } A.prototype.myFunc = function(){ var newVar = this.prop1; //newVar now is equivalent to 1 } var instanceOfA = new A(); v
function A(){
var prop1 = 1;
}
A.prototype.myFunc = function(){
var newVar = this.prop1; //newVar now is equivalent to 1
}
var instanceOfA = new A();
var newVar2 = instanceOfA.prop1; //error given as prop1 is "protected"; hence undefined in this case
顺便说一句-我不希望特权成员函数访问私有属性的模式,因为成员函数仍然是公共的。这可能就是您要寻找的:您不能在Javascript中进行访问。没有对象属性只能从
A
的原型方法访问,而不能从A
的非原型方法。该语言没有这种类型的功能,我也不知道有什么解决方法/黑客来实现它
使用,可以创建只能从预定义的非原型方法(构造函数中定义的方法)访问的成员属性。因此,如果您试图将访问权限限制在预定义的一组方法上,这将实现这一点。除此之外,我认为你运气不好
如果您想要其他想法,那么如果您更多地描述您在代码中实际试图实现的目标,而不仅仅是如何用另一种语言模拟某个特性,您可能会得到更多的帮助。JavaScript与C++相比有很大的不同,最好是从问题的需要出发,而不是试图找到一些C++特性的类比。 < P>看看MKS在他的网站上提出的解决方案:
它模拟受保护对象的方法和属性的访问级别。我找到了一种创建受保护成员的方法。因此,我调用基本构造函数,同时返回一个包含受保护成员的对象:
var protected = BaseClass.call(this);
这里有一个例子:
function SignedIntegerArray(size)
{
var public = this;
var protected = {};
// private property:
var _maxSize = 10000;
// protected property:
protected.array = [];
// public property:
public.Length = size;
if(!isInteger(size) || size < 0 || size > _maxSize) { throw "argument exception"; }
for(var index = 0; index != size; index++) { protected.array[index] = 0; }
// private method:
function isInteger(i) { return i == i + 0 && i == ~~i; }
// protected method:
protected.checkIndex = function(index) { return index >= 0 && index < size; }
// public methods:
public.SetValue = function(index, value) { if(protected.checkIndex(index) && isInteger(value)) { protected.array[index] = value; } };
public.GetValue = function(index) { if(protected.checkIndex(index)) { return protected.array[index]; } else { throw "index out of range exception"; }}
return protected;
}
function FloatArray(size, range)
{
var public = this;
var protected = SignedIntegerArray.call(this, size); // call the base constructor and get the protected members
// new private method, "isInteger" is hidden...
function isFloat(argument) { return argument != ~~argument; }
// ...but "checkIndex" is accessible
public.SetValue = function(index, value) { if(protected.checkIndex(index) && isFloat(value) && value >= public.MinValue && value <= public.MaxValue) { protected.array[index] = value; } };
// new public properties:
public.MinValue = -range;
public.MaxValue = range;
return protected; // for sub-classes
}
function newObject(className, args) { return new function() { className.apply(this, args)}} // you need to use function.call or function.apply to initialize an object. otherwise the protected-object is empty.
window.addEventListener("load", function()
{
var o = newObject(FloatArray, [4, 50.0]);
o.SetValue(3, 2.1);
console.log(o.GetValue(3));
console.log(o.Length); // property from the base-class
});
// That's the default extends function from typescript (ref: http://www.typescriptlang.org/)
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var BaseClass = (function () {
function BaseClass() {
// Members
var private = {},
protected = {},
public = this;
// Constructor
ProtectedHandler.handle(protected, arguments, function () {
protected.type = "BaseClass";
}, true);
// Methods
protected.saySomething = function () {
return "Hello World";
};
public.getType = function () {
return protected.type;
};
}
return BaseClass;
})();
var Person = (function (_super) {
__extends(Person, _super);
function Person(name) {
// Members
var private = {},
protected = {},
public;
// Constructor
_super.call(public = this, ProtectedHandler.handle(protected, arguments, function (p) {
protected = p; //This is required to copy the object from its base object.
protected.name = name;
protected.type = "Person";
}));
//Method
public.getName = function () {
return protected.name;
};
public.saySomething = function () {
return protected.saySomething();
};
}
return Person;
})(BaseClass);
var Child = (function (_super) {
__extends(Child, _super);
function Child(name) {
// Members
var private = {},
protected = {},
public;
// Constructor
_super.call(public = this, name, ProtectedHandler.handle(protected, arguments, function (p) {
protected = p; //This is required to copy the object from its base object.
protected.type = "Child";
}));
//Method
public.setName = function (value) {
return protected.name = value;
};
}
return Child;
})(Person);
函数签名集成阵列(大小)
{
var public=this;
var-protected={};
//私人财产:
var_maxSize=10000;
//受保护财产:
protected.array=[];
//公共财产:
公共。长度=大小;
如果(!isInteger(size)| | size<0 | | size>_maxSize){抛出“参数异常”;}
对于(var index=0;index!=size;index++){protected.array[index]=0;}
//私人方法:
函数isInteger(i){返回i==i+0&&i==i;}
//保护方法:
protected.checkIndex=函数(index){return index>=0&&index public.SetValue=function(index,value){if(protected.checkIndex(index)&&isFloat(value)&&value>=public.MinValue&&value我很想找到一种方法来回答你的问题,下面是我能做的
您将需要此帮助程序:
var ProtectedHandler = (function () {
/// <Sumarry>
/// Tool to handle the protected members of each inheritance.
/// </Summary>
/// <param name="current">Current protected variable.</param>
/// <param name="args">The arguments variable of the object.</param>
/// <param name="callback">The function to initialise the variable in the 'object'.</param>
/// <param name="isParent">Is this the ultimate base object.</param>
function ProtectedHandler(current, args, callback, isParent) {
this.child = getChild(args);
if (callback)
this.callback = callback;
if (isParent)
this.overrideChild(current);
}
// Get the ProtectedHandler from the arguments
var getChild = function (args) {
var child = null;
if (args.length > 0 && (child = args[args.length - 1]) && child.constructor === ProtectedHandler)
return child;
};
// Chain Initialise the protected variable of the object and its inheritances.
ProtectedHandler.prototype.overrideChild = function (newValue) {
if (this.callback != null) {
this.callback(newValue);
}
if (this.child != null) {
this.child.overrideChild(newValue);
}
};
// Static function to create a new instance of the protectedHandler object.
ProtectedHandler.handle = function (protected, arguments, callback, isParent) {
return new ProtectedHandler(protected, arguments, callback, isParent);
};
return ProtectedHandler;
})();
以下是测试:
var testBase = new BaseClass();
testBase.getType(); //"BaseClass"
testBase.saySomething; //undefined
var testPerson = new Person("Nic");
testPerson.getType(); //"Person"
testPerson.saySomething(); //"Hello World"
testPerson.name; //undefined
testPerson.getName() //"Nic"
testPerson.setName; //undefined
var testChild = new Child("Bob");
testChild.getType(); //"Child"
testChild.saySomething(); //"Hello World"
testChild.name; //undefined
testChild.getName(); //"Bob"
testChild.setName("George");
testChild.getName(); //"George"
我喜欢的一种模式与大多数语言中受保护访问的工作方式不同,但提供了类似的好处
基本上,使用生成器方法为属性创建闭包,然后让该方法创建具有自由访问权限的“完整”对象以及具有更有限访问权限的“公开”对象。将公开对象放入完整对象的属性中,并将该完整对象返回给调用者
然后,调用方可以使用完整对象(并将其传递给其他适当的协作者),但只将公开的对象提供给应该具有更严格访问权限的协作者
一个人为的例子
// Ring employs a typical private/public pattern while
// RingEntry employs a private/exposed/full access pattern.
function buildRing( size ) {
var i
, head = buildRingEntry( 0 )
, newEntry;
;
head.setNext( head );
for( i = size - 1; i ; i-- ) {
newEntry = buildRingEntry( i );
newEntry.setNext( head.getNext() );
head.setNext( newEntry );
}
function getHead() { return head.exposed; }
return {
getHead : getHead
}
}
function buildRingEntry( index ) {
var next
, exposed
;
function getIndex() { return index; }
function setNext( newNext ) { next = newNext; }
function getNextFullEntry() { return next; }
function getNextExposedEntry() { return next.exposed; }
exposed = {
getIndex : getIndex
, getNext : getNextExposedEntry
};
return {
getIndex : getIndex
, setNext : setNext
, getNext : getNextFullEntry
, exposed : exposed
};
}
如果我们用它来构建一个由4个条目组成的环,ring=buildRing(4);
,那么ring.getHead().getIndex()给我们0,ring.getHead().getNext().getIndex()给我们1,ring.getHead().getNext().getNext().getIndex()给我们2,等等
但是,如果尝试执行ring.getHead().setNext({})
或ring.getHead().getNext().setNext({})
,则会出现错误,因为setNext
不是公开条目对象的属性
警告:
由于这是在为每个新对象重新构建新闭包中的方法的模式家族中,因此它不适用于可能需要大量实例化的情况。我的建议通常是不要强制查看JavaScript。闭包等可以实现某些功能,但语言不是设计的这将使你的代码更加复杂。相反,将你的方法正确地记录为私有或公共的,如果其他开发人员不遵循你的规范,这是他们的问题。顺便说一句,原型对象可以被扩充(它们不是密封的)-没有什么可以阻止入侵者向prototype对象添加新方法。因此,仅通过prototype方法访问属性并不安全(即使可能)JavaScript不是面向类的,它是面向对象的——不是面向对象的,而是指类实例,而是在……对象的意义上。没有像通常的类成员关键字在java或C++中的特性,而是需要基于语言的对象和事件驱动性质来设计实现。是基于ES6中新特性的解决方案。例如,请参见此处:我同意。Doug Crockford的文章是
// Ring employs a typical private/public pattern while
// RingEntry employs a private/exposed/full access pattern.
function buildRing( size ) {
var i
, head = buildRingEntry( 0 )
, newEntry;
;
head.setNext( head );
for( i = size - 1; i ; i-- ) {
newEntry = buildRingEntry( i );
newEntry.setNext( head.getNext() );
head.setNext( newEntry );
}
function getHead() { return head.exposed; }
return {
getHead : getHead
}
}
function buildRingEntry( index ) {
var next
, exposed
;
function getIndex() { return index; }
function setNext( newNext ) { next = newNext; }
function getNextFullEntry() { return next; }
function getNextExposedEntry() { return next.exposed; }
exposed = {
getIndex : getIndex
, getNext : getNextExposedEntry
};
return {
getIndex : getIndex
, setNext : setNext
, getNext : getNextFullEntry
, exposed : exposed
};
}