如何在 JavaScript 中创建受保护的对象属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8044186/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to Create Protected Object Properties in JavaScript
提问by Drake Amara
Is there a JavaScript pattern which mimics "Protected" object properties like what you see in languages like C++ ??
是否有一种 JavaScript 模式可以模仿“受保护的”对象属性,就像您在 C++ 等语言中看到的那样?
Basically, I'd like to create an Object A which has a number of "protected" object properties which can be accessed ONLY from methods which are defined from the prototype of Object A. i.e. - NOT accessible publicly from non-prototyped methods of A.
基本上,我想创建一个对象 A,它具有许多“受保护”的对象属性,这些属性只能从对象 A 的原型定义的方法访问。即 - 不能从 A 的非原型方法公开访问.
For instance, ideally would be like so:
例如,理想情况下是这样的:
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 - I do not want the pattern of privileged member functions accessing private properties since the member function is still public.
顺便说一句 - 我不希望特权成员函数访问私有属性的模式,因为成员函数仍然是公共的。
采纳答案by jfriend00
There is no object property that can only be accessed from prototyped methods of A
and not from non-prototyped methods of A
. The language doesn't have that type of feature and I'm not aware of any work-around/hack to implement it.
没有对象属性只能从 的原型方法访问A
,而不能从 的非原型方法访问A
。该语言没有这种类型的功能,我不知道任何解决方法/黑客来实现它。
Using Doug Crockford's methods, you can create member properties that can only be accessed from predefined non-prototyped methods (those defined in the constructor). So, if you're trying to limit access only to a predefined set of methods, this will accomplish that. Other than that, I think you're out of luck.
使用Doug Crockford 的方法,您可以创建只能从预定义的非原型方法(在构造函数中定义的方法)访问的成员属性。因此,如果您试图将访问限制为仅对一组预定义的方法,这将实现这一目标。除此之外,我认为你不走运。
If you want other ideas, you'd probably get more help if you describe more about what you're actually trying to accomplish in your code rather than just how to emulate a feature in another language. Javascript is so much different than C++ that it's better to start from the needs of the problem rather than try to find an analogy to some C++ feature.
如果您想要其他想法,如果您更多地描述您在代码中实际尝试完成的工作,而不仅仅是如何用另一种语言模拟功能,您可能会获得更多帮助。Javascript 与 C++ 有很大不同,所以最好从问题的需要出发,而不是试图找到与某些 C++ 特性的类比。
回答by Thomas Eding
You cannot do it in Javascript.
你不能在 Javascript 中做到这一点。
回答by Martin Wantke
I found a way for creating protected members. Therefor I call the base constructor and return an object with the protected members at the same time:
我找到了一种创建受保护成员的方法。因此,我调用基本构造函数并同时返回一个具有受保护成员的对象:
var protected = BaseClass.call(this);
Here an example:
这里有一个例子:
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
});
回答by Ericson578
This is probably what you're looking for: http://javascript.crockford.com/private.html
这可能就是你要找的:http: //javascript.crockford.com/private.html
回答by Martin Wantke
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();
回答by Finickyflame
I was interested to find a way to answer your question, and here's what I was able to do.
我很想找到一种方法来回答您的问题,这就是我能够做的。
You'll need this helper:
你需要这个帮手:
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;
})();
This helper will allow you to handle multiple inheritances. The trick is to copy the protected variable from the base object to your new object (child).
这个助手将允许您处理多重继承。诀窍是将受保护的变量从基础对象复制到新对象(子对象)。
To prove you it's working, here's an example:
为了证明它有效,这里有一个例子:
// 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);
And here's the tests:
这是测试:
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"
回答by Steve Jorgensen
There is a pattern that I have come to like that does not work the same way as protected access does in most languages, but provides a similar benefit.
我开始喜欢一种模式,它的工作方式与大多数语言中的受保护访问不同,但提供了类似的好处。
Basically, use a builder method to create a closure for properties, and then have that method create a "full" object with liberal access as well as an "exposed" object with more limited access. Place the exposed object into a property of the full object, and return that full object to the caller.
基本上,使用构建器方法为属性创建一个闭包,然后让该方法创建一个具有自由访问权限的“完整”对象以及一个具有更有限访问权限的“公开”对象。将暴露的对象放入完整对象的属性中,并将该完整对象返回给调用者。
The caller can then make use of the full object (and pass that to other appropriate collaborators), but provide only the exposed object to collaborators that should have the more restricted access.
然后调用者可以使用完整的对象(并将其传递给其他适当的合作者),但仅将公开的对象提供给应该具有更受限访问权限的合作者。
A contrived example…
一个人为的例子……
// 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
};
}
If we use that to build a ring of 4 entries ring = buildRing(4);
, then ring.getHead().getIndex()
gives us 0, ring.getHead().getNext().getIndex()
gives us 1, ring.getHead().getNext().getNext().getIndex()
gives us 2, etc.
如果我们用它来构建一个包含 4 个条目的环ring = buildRing(4);
,那么ring.getHead().getIndex()
给我们 0,ring.getHead().getNext().getIndex()
给我们 1,ring.getHead().getNext().getNext().getIndex()
给我们 2,等等。
If we try to execute ring.getHead().setNext({})
or ring.getHead().getNext().setNext({})
, however, we get an error because setNext
is not a property of an exposed entry object.
然而,如果我们尝试执行ring.getHead().setNext({})
or ring.getHead().getNext().setNext({})
,我们会得到一个错误,因为setNext
它不是暴露的条目对象的属性。
Caveat:
警告:
Since this is in the family of patterns that build the methods again in a new closure for each new object, it is not suitable for situations in which a very high volume of instantiation may be needed.
由于这是在为每个新对象在新闭包中再次构建方法的模式家族中,因此它不适合可能需要大量实例化的情况。
回答by Roman
Take a look at workaround proposed by Maks on his website: Emulating protected members in JavaScript
看看 Maks 在他的网站上提出的解决方法:Emulating protected members in JavaScript
It emulates protected
access level to methods and properties of an object.
它模拟protected
对象的方法和属性的访问级别。