Javascript对象中大多数私有/受保护方法的问题是,它们使用闭包。这样,它们必须在构造函数中定义,并且所有想要访问它们的公共方法也必须在构造函数中定义。
这使得两件事变得不可能:
有没有办法解决这两个问题,因此可以在所有实例之间共享私有方法,以及子级能够重用其父级保护方法。
同样不错的浏览器支持,至少在ECMA5级别上会很棒。
答案 0 :(得分:0)
虽然这可能不是一个完美而优雅的解决方案,但我找到了解决上述问题的方法
首先看看我们的构造函数,以及一些原型方法。
function FooConstructor(args) {
this.args = args;
this.private = "lower case secret from foo";
this.exports = {
publicMethod: this.publicMethod.bind(this)
};
}
FooConstructor.prototype.privateMethod = function() {
return this.private;
}
FooConstructor.prototype.publicMethod = function() {
return this.privateMethod().toUpperCase();
}
不是对象this.exports
。在这里,我们将存储应该公开的所有内容。
重要的是,我们不直接调用构造函数,而是使用Factorymethod,它获取对象的实例,然后只返回exports
对象。
function getInstanceFoo(args) {
return new FooConstructor(args).exports;
}
现在,如果我们想要一个Foo实例,我们就可以了。
var fooInstance = getInstanceFoo("fooArg");
从这个实例中我们只能访问我们放入exports
对象的内容。
fooInstance.publicMethod(); // "LOWER CASE SECRET FROM FOO"
fooInstance.private; // undefined
fooInstance.privateMethod; // undefined
// calling it would give you:
// Uncaught TypeError: fooInstance.privateMethod is not a function
现在好处是,我们的工厂只出口我们想要公开的东西,但我们仍然有一个可以访问的构造函数。所以对于一个孩子,我们可以这样做:
function BarConstructor(args) {
// this will just copy all the exported methods from Foo
FooConstructor.call(this, args);
// overwrite stuff we don’t want from the parents constructor
this.privateMember = "lower case secret from bar";
// add publics that should be exported for the child
this.exports.newPublicMethod = this.newPublicMethod.bind(this);
}
BarConstructor.prototype = new FooConstructor();
BarConstructor.prototype.newPublicMethod = function() {
return "My args: " + this.args;
}
function getInstanceBar(args) {
return new BarConstructor(args).exports;
}
var barInstance = getInstanceBar("barArg");
barInstance.publicMethod(); // "LOWER CASE SECRET FROM BAR"
barInstance.newPublicMethod(); // "My args: barArg"
barInstance.private; // undefined
就是这样。这几乎是我们想要的。 在这里你可以尝试一下:
// FooConstructor ------------------------------------------
function FooConstructor(args) {
this.args = args;
this.privateMember = "lower case secret from foo";
this.exports = {
publicMethod: this.publicMethod.bind(this)
};
}
FooConstructor.prototype.privateMethod = function() {
return this.privateMember;
}
FooConstructor.prototype.publicMethod = function() {
return this.privateMethod().toUpperCase();
}
// FooFactory
function getInstanceFoo(args) {
return new FooConstructor(args).exports;
}
// BarConstructor ------------------------------------------
function BarConstructor(args) {
// this will just copy all the exported methods from Foo
FooConstructor.call(this, args);
this.privateMember = "lower case secret from bar";
this.exports.newPublicMethod = this.newPublicMethod.bind(this);
}
BarConstructor.prototype = new FooConstructor();
BarConstructor.prototype.newPublicMethod = function() {
return "My args: " + this.args;
}
// BarFactory
function getInstanceBar(args) {
return new BarConstructor(args).exports;
}
// Get Instances ------------------------------------------
var fooInstance = getInstanceFoo("fooArg"),
barInstance = getInstanceBar("barArg");
console.log( "fooInstance.publicMethod(): " + fooInstance.publicMethod() );
console.log( "fooInstance.private: " + fooInstance.private );
console.log( "fooInstance.privateMethod: " + fooInstance.privateMethod );
console.log( "barInstance.publicMethod(): " + barInstance.publicMethod() );
console.log( "barInstance.newPublicMethod(): " + barInstance.newPublicMethod() );
console.log( "barInstance.private: " + barInstance.private );

有一些东西,可能是缺点,即使有可能为那些找到工作。你必须决定这些是否是交易破坏者。
instanceof
无效。
fooInstance instanceof FooConstructor; // false
bind
如果您担心bind
会降低您的程序速度并且开销不是可行的,那么您可以通过将构造函数更改为此来返回非私有版本:
function getInstanceBar(args) {
return new BarConstructor(args);
}
从构造函数中删除this.exports
。因此,您可以轻松地在两者之间切换,而无需进行太多重构。同样在这种情况下,向所有私有成员添加下划线可能是个好主意。