是否存在模仿“受保护”对象属性的JavaScript模式,就像您在C ++等语言中看到的那样?
基本上,我想创建一个具有许多“受保护”对象属性的对象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();
var newVar2 = instanceOfA.prop1; //error given as prop1 is "protected"; hence undefined in this case
BTW - 我不希望特权成员函数的模式访问私有属性,因为成员函数仍然是公共的。
答案 0 :(得分:12)
没有对象属性只能从A
的原型方法访问,而不能从A
的非原型方法访问。该语言没有这种类型的功能,我不知道任何解决方法/黑客实现它。
使用Doug Crockford's methods,您可以创建只能从预定义的非原型方法(构造函数中定义的方法)访问的成员属性。因此,如果您尝试仅限制访问一组预定义的方法,则可以实现此目的。除此之外,我认为你运气不好。
如果您想要其他想法,如果您更多地了解您在代码中实际尝试完成的内容,而不仅仅是如何使用其他语言模拟某个功能,则可能会获得更多帮助。 Javascript与C ++有很大的不同,最好从问题的需要开始,而不是试图找到一些C ++特性的类比。
答案 1 :(得分:9)
你不能用Javascript。
答案 2 :(得分:5)
我找到了创建受保护成员的方法。因此,我调用基础构造函数并同时返回带有受保护成员的对象:
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
});
答案 3 :(得分:4)
这可能是您正在寻找的内容:http://javascript.crockford.com/private.html
答案 4 :(得分:2)
function ClassA(init)
{
var protected = {};
protected.prop = init * 10;
if(this.constructor != ClassA) { return protected; }
}
function ClassB()
{
var protected = ClassA.call(this, 5); //console.log(protected.prop);
}
//var a = new ClassA(123);
//var b = new ClassB();
答案 5 :(得分:1)
我有兴趣找到一种方法来回答你的问题,这就是我能做的事情。
你需要这个帮手:
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;
})();
此助手将允许您处理多个继承。诀窍是将受保护的变量从基础对象复制到新对象(子)。
为了证明你的工作,以下是一个例子:
// 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 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"
答案 6 :(得分:1)
我所喜欢的模式与大多数语言中的受保护访问方式不同,但提供了类似的好处。
基本上,使用构建器方法为属性创建闭包,然后让该方法创建一个&#34; full&#34;自由访问的对象以及&#34;暴露的&#34;访问权限受限的对象。将公开的对象放入完整对象的属性中,并将该完整对象返回给调用者。
然后,调用者可以使用完整对象(并将其传递给其他适当的协作者),但仅向应该具有更多限制访问权限的协作者提供公开的对象。
一个人为的例子......
// 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
不是公开的条目对象的属性。
警告:
由于这是在每个新对象的新闭包中再次构建方法的模式族,因此它不适用于可能需要非常大量实例化的情况。
答案 7 :(得分:0)
看看Maks在他的网站上提出的解决方法:Emulating protected members in JavaScript
它模拟对象的方法和属性的protected
访问级别。