[英]prototype closure in the constructor
更新:
這種實現方式很糟糕,我已經刪除了該答案。
我只是回答了這個問題 。 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
並清理了對對象的所有A.prototype.myFunc
引用A.prototype.myFunc
,也存在疑問,當gc出現時它可能仍然存在。 所以我認為這個問題的答案可能是:
答:一種更可行的方法來更改構造函數中的原型方法,以實現只能在原型方法中訪問私有成員。
B.實現相同目的的另一種方法,並且代碼盡可能地簡單。
指出我對您的答案中的閉包和垃圾回收的誤解也將不勝感激。
讓我們在另一個問題中查看OP的要求:
是否存在模仿“受保護”對象屬性的JavaScript模式
答:最好的方式(以我的觀點)將它們命名為_myPrivate
順便說一句-我不希望特權成員函數的模式訪問私有屬性,因為成員函數仍然是公共的。
這根本沒有任何意義,OP認為A.prototype.myFunc
無法在A實例上公開訪問嗎?
可以在此處找到原型和構造函數的簡介(以及一些私有模式)
我傾向於人們說同意“只是不帶私人打擾”,但我認為要做到這一點的最好辦法,如果你真的想要的話,是有Function#bind
。 Crockford的文章沒有提到這種方法,可能是因為它早於bind
,而用apply
模擬bind
有點毛茸茸(或者可能是因為額外的開銷並沒有太多收益)。
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
1。 它需要一個額外的功能來確保不對此進行引用。
沒有解決方法。 that
是通過捕獲A.prototype.myFunc
每個實例中,與實例本身是可以訪問的對象that
直接,更對象涉及只會讓事情變得更糟; retire
方法已經是取消引用的最簡單方法。
2。 之后,隨着對象的創建,A.prototype.myFunc越來越大。
這只是潛在的風險。 A.prototype.myFunc
與遞歸方法類似,但實際上並非如此 。 它調用前一個myFunc
並檢查實例的身份。 在少數情況下這不是問題,但在許多情況下,深度的增加最終會導致堆棧溢出 。
由於實現將需要任何清理機制,因此使調用更深層次的內容不會僅使用數組來保存引用並按需清理而獲得任何好處。
3。 由於每個var myFunc仍由A.prototype.myFunc引用,因此即使在調用retire並清理了對對象的所有外部引用之后,也存在疑問,當gc出現時它可能仍然存在。
事實是A.prototype.myFunc
捕獲的var myFunc
仍然存在,即使gc來收集垃圾。 幾乎不可能釋放對myFunc
的引用,因為它是鏈式調用,更深層調用和淺層調用的上下文彼此不可見,因此它們都不能夠修改調用鏈用於跳過水平 ; 取消設置myFunc
只會破壞鏈條。 任何試圖解決此問題的技巧都將涉及更多對象,這可能會增加成本,也可能會顯得過大。
4。 我的測試環境有限,很高興知道此實現是否存在潛在風險。
作為要點2的答案,當使用它創建許多對象時,它可能導致堆棧溢出。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.