更新:
这种实现很糟糕,我已经删除了这个答案。
我刚回答this question。 OP要求私有成员的解决方案,只能通过原型方法访问。对于我的回答,我不建议这样做,而是提出其可能性的代码。 (对不起,我对标题没有好主意......)
代码
function A(prop1) {
var myFunc=A.prototype.myFunc;
var that=this;
A.prototype.myFunc=function () {
if (this===that) {
alert(prop1); // do something
}
else {
myFunc.call(this);
}
};
this.retire=function () {
that=undefined;
};
}
A.prototype.myFunc=function () {
};
var a1=new A(1);
var a2=new A(2);
var a3=new A(3);
a1.myFunc();
a2.myFunc();
a3.myFunc();
a2.retire();
a1.myFunc();
a2.myFunc();
a3.myFunc();
// ..
我们可以看到是否有其他原型方法可以访问prop1
,需要重复这种模式。我曾经想过使用私有数组来实现它,但这段代码似乎要短得多。
但有些事情并不好:
that
不引用this
。 A.prototype.myFunc
正在成长(更深)。 var myFunc
仍然引用了每个A.prototype.myFunc
,因此即使在调用retire
并清除对象的所有外部引用之后也存在疑问,当gc出现时它可能仍然存在。 所以我认为这个问题的答案可能是:
一个。一种更可行的方法来改变构造函数中的原型方法,以实现私有成员只能在原型方法中访问。
B中。另一种实现同样的方法,并且代码尽可能简单。
我还要非常感激地指出我对你的答案中的闭包和垃圾收集的误解。
答案 0 :(得分:1)
让我们在另一个问题中看到OP的要求:
是否存在模仿“受保护”对象的JavaScript模式 特性
答案:某种,最好的方式(在我看来)将它们命名为_myPrivate
BTW - 我不想要特权成员函数的模式 因为成员函数仍然存在,所以访问私有属性 公共
根本没有任何意义,OP是否认为A.prototype.myFunc
在A个实例上无法公开访问?
可以找到原型和构造函数的介绍(以及私有的一些模式)here
答案 1 :(得分:1)
我倾向于同意那些说“只是不打扰私人”的人,但我认为,如果你真的想要它,最好的方法就是{{1} }。 Crockford的文章没有提到这种方法,可能是因为它早于Function#bind
,并且用bind
模仿bind
会有点毛茸茸(或者可能是因为它的额外开销不大增益)。
apply
此功能允许您定义具有“公共”和“私有”范围的伪类。这个想法是:
首次尝试
function classify(fn) {
var privateScope = {}, publicScope = {};
function bindProp(to, target, src, key) {
if (!src.hasOwnProperty(key)) return;
if (!(src[key] && src[key].bind)) return;
target[key] = src[key].bind(to);
}
function ctor() {
var instancePublic = {}, instancePrivate = Object.create(instancePublic);
for (var key in publicScope) {
bindProp(instancePrivate, instancePublic, publicScope, key);
}
for (var key in privateScope) {
instancePrivate[key] = privateScope[key];
}
if (publicScope.hasOwnProperty('constructor'))
publicScope.constructor.apply(instancePrivate, arguments);
return instancePublic;
}
fn.call(publicScope, publicScope, privateScope);
return ctor;
}
此版本的原型链反转:
function classify(fn) {
var privateScope = {}, publicScope = {};
function bindProp(privateScope, scopeObject, key) {
if (!scopeObject.hasOwnProperty(key)) return true;
if (!(scopeObject[key] && scopeObject[key].bind)) return;
privateScope[key] = scopeObject[key].bind(privateScope);
}
function ctor() {
var instancePrivate = Object.create(privateScope),
instancePublic = Object.create(instancePrivate);
for (var key in publicScope) {
console.log(key);
bindProp(instancePrivate, publicScope, key);
}
for (var key in privateScope) {
if (!bindProp(instancePrivate, privateScope, key)
&& !publicScope.hasOwnProperty(key))
instancePublic[key] = void 0;
}
if (publicScope.hasOwnProperty('constructor'))
publicScope.constructor.apply(instancePrivate, arguments);
return instancePublic;
}
fn(publicScope, privateScope);
return ctor;
}
遮蔽。<强>用法强>
您可以使用以下内容:
undefined
你可以在控制台中玩这个,看看它的效果就像你可能期望的那样。
var Foo = classify(function(pub, priv) {
// constructors are supported but not required
pub.constructor = function(a, b) {
this.a = a;
this.b = b;
};
priv.somePrivateProp = "lol";
priv.doPrivateStuff = function(x, y) {
return x + y;
};
pub.somePublicProp = "rofl";
pub.doStuff = function(x, y) {
return this.doPrivateStuff(x + 1, y + 1) + ' ' + this.somePrivateProp;
};
});
答案 2 :(得分:1)
1。它需要一个额外的功能,以确保不参考这一点。
没有解决方法。 that
在每个实例化中捕获A.prototype.myFunc
,实例本身就是可以直接访问that
的对象,涉及的对象越多,就会使事情变得更糟; retire
方法已经是解开引用的最简单方法。
2。 A.prototype.myFunc随着对象的创建而成长(更深)。
这只是潜在的风险。 A.prototype.myFunc
与递归方法类似,但实际上不是。它调用前一个myFunc
并检查实例的身份。对于少数情况,这不是问题,但对于大量实例,增长的深度最终将导致堆栈溢出。
由于实现将需要一个清理机制,为了使调用更深入,只需使用数组来保存引用,并按需清理。
3。因为每个var myFunc仍然被A.prototype.myFunc引用,所以即使在调用了退出并清理对象的所有outter引用之后也存在疑问,当gc到来时它可能仍然存在。
即使gc来收集垃圾,var myFunc
捕获的A.prototype.myFunc
仍然存活。几乎不可能可以释放对myFunc
的引用,因为它是链式调用,更深层调用的上下文和浅层调用没有相互之间的可见性,因此它们都不能修改跳过级别的调用链; unset myFunc
只会破坏链条。试图解决这个问题的任何技巧都会涉及更多的对象,这可能会增加成本或者成为一种过度杀伤力。
4。我的测试环境有限,很高兴知道这种实现是否存在潜在的风险。
作为第2点的答案,当用它创建大量对象时,它可能导致堆栈溢出。