我傾向於人們說同意「只是不帶私人打擾」,但我認爲最好的方法要做到這一點,如果你真的想要它,是用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;
};
});
您可以在控制檯玩這個,看看它就像你可能會想到。
var foo = new Foo('abc', 123);
foo.doStuff(3, 5); // "10 lol"
foo.doPrivateStuff(3, 5) // throws TypeError
您將實例之間共享方法的整個想法割裂開來。只是做'this.myFunc = function(){alert(prop1); };構造函數內部。它沒有利用原型,但你的方法不是。 – Tibos
@Tibos:你說得對。代碼只是爲了這個要求的可能性。 –