概念解析:
revealing-constructor pattern
揭示性的建構(gòu)模式
Promise 對(duì)構(gòu)造函數(shù)提供私有方法(顯示構(gòu)造函數(shù)模式)的標(biāo)準(zhǔn)方式進(jìn)行了修改。
私有方法是在創(chuàng)建對(duì)象時(shí)作為閉包創(chuàng)建的方法。這是用于創(chuàng)建可從對(duì)象內(nèi)部而不是外部訪問(wèn)的私有變量的標(biāo)準(zhǔn)方法留瞳。唯一的區(qū)別是變量引用了一個(gè)函數(shù)。如:
function myConstructor(){
var private=0;
this.myFunction=function(){
alert(private);
}
}
這是僅使用一種方法myFunction的對(duì)象的構(gòu)造函數(shù)肾筐。
重要的部分是稱為private的變量慷吊。這不是對(duì)象的一部分馍惹,因?yàn)樗鼪](méi)有聲明為對(duì)象的屬性瑞眼。因此龙宏,如果您嘗試:
var myObject=new myConstructor(); myObject.private=1;
您將看到一個(gè)不存在 private 的錯(cuò)誤。但是伤疙,由于在聲明 myFunction 時(shí)在范圍內(nèi)是private银酗,因此可以將其作為閉包使用:
myObject.myFunction();
確實(shí)顯示private的值。
私有方法使用相同的機(jī)制徒像,所不同的是變量引用了一個(gè)函數(shù)-一個(gè)內(nèi)部函數(shù)黍特,該內(nèi)部函數(shù)不是正在構(gòu)造的對(duì)象的方法。
這是JavaScript Promise用來(lái)解析和拒絕私有方法的機(jī)制锯蛀,但有一些其他的變化灭衷。
私有函數(shù)和變量由傳遞給構(gòu)造函數(shù)的函數(shù)訪問(wèn)。
讓我們看看它是如何工作的旁涤。
假設(shè)您需要將私有變量設(shè)置為某個(gè)值翔曲,但僅在使用構(gòu)造函數(shù)時(shí)才需要。
最簡(jiǎn)單的解決方案是:
function myClass(value){
var myPrivateVar=value;
this.myMethod=function(){
console.log(myPrivateVar);
}
}
現(xiàn)在拭抬,您可以使用以下方法創(chuàng)建實(shí)例:
var myObject=new myClass(10);
myObject.myMethod();
將打印私有變量的值部默,即10,并且在使用構(gòu)造函數(shù)時(shí)已設(shè)置了該變量造虎,但是該變量現(xiàn)在無(wú)法通過(guò)對(duì)象外部的代碼進(jìn)行更改。
這似乎很簡(jiǎn)單纷闺,但是如果我們進(jìn)一步推動(dòng)這個(gè)想法算凿,就會(huì)變得更加困難。
如果要在構(gòu)造函數(shù)調(diào)用中傳遞與正在構(gòu)造的對(duì)象的私有成員一起使用的函數(shù)犁功,會(huì)發(fā)生什么情況氓轰?該函數(shù)旨在由構(gòu)造函數(shù)在創(chuàng)建對(duì)象時(shí)執(zhí)行。
第一次嘗試可能是這樣的:
function myClass(func) {
var myPrivateVar = Math.random();
var reveal = function (){
return myPrivateVar;
}
func();
}
這將創(chuàng)建一個(gè)設(shè)置為隨機(jī)值的私有變量浸卦,可以通過(guò)訪問(wèn)私有方法揭示來(lái)發(fā)現(xiàn)該私有變量署鸡。想法是func是一個(gè)傳遞給構(gòu)造函數(shù)然后執(zhí)行的函數(shù),可以利用reveal訪問(wèn)該值。
如果通過(guò)傳遞給它一個(gè)嘗試?yán)媒沂镜暮瘮?shù)來(lái)進(jìn)行嘗試:
var myObject = new myClass(
function () { console.log(reveal()); }
);
當(dāng)調(diào)用 func 時(shí)靴庆,您將看到一條錯(cuò)誤消息时捌,提示 reveal 未定義。
這里的錯(cuò)誤是顯而易見(jiàn)的炉抒,表明不在傳遞給構(gòu)造函數(shù)的函數(shù)范圍內(nèi)奢讨。函數(shù)可以訪問(wèn)哪些變量取決于函數(shù)的聲明位置,而不是使用位置焰薄。解決該錯(cuò)誤的方法非常簡(jiǎn)單–將所需的私有成員作為參數(shù)傳遞給函數(shù)拿诸。
就是:
var myObject = new myClass(
function (reveal) { console.log(reveal()); }
);
現(xiàn)在注意,該函數(shù)需要在構(gòu)造函數(shù)中使用參數(shù)進(jìn)行調(diào)用:
function myClass(func) {
var myPrivateVar = Math.random();
var reveal = function () { return myPrivateVar;};
func(reveal);
}
現(xiàn)在一切正常塞茅。傳遞給構(gòu)造函數(shù)的函數(shù)可以調(diào)用私有函數(shù)亩码,只要它們?cè)谡{(diào)用函數(shù)時(shí)傳遞給私有函數(shù)即可。
一般原則是:
- 對(duì)象的構(gòu)造函數(shù)中的局部變量以及內(nèi)部函數(shù)是該構(gòu)造函數(shù)及其構(gòu)造的對(duì)象的私有屬性野瘦。
- 對(duì)象可以通過(guò)閉包訪問(wèn)這些私有變量蟀伸。
- 通過(guò)傳遞參數(shù)調(diào)用構(gòu)造函數(shù)的代碼可以訪問(wèn)私有成員。
- 如果調(diào)用構(gòu)造函數(shù)的代碼傳遞了由構(gòu)造函數(shù)執(zhí)行的函數(shù)缅刽,則此函數(shù)將無(wú)法訪問(wèn)私有變量啊掏,因?yàn)槎x函數(shù)時(shí)它們不在范圍內(nèi)。
- 但是衰猛,可以在構(gòu)造函數(shù)調(diào)用函數(shù)時(shí)將私有變量傳遞給函數(shù)迟蜜,因?yàn)樗鼈冊(cè)谧饔糜騼?nèi)。
注意啡省,您也可以這樣寫:
var myObject = new myClass(
function (privateFunction) {
console.log(privateFunction());
}
);
該函數(shù)的名稱只是第一個(gè)參數(shù)傳遞的占位符娜睛。該函數(shù)實(shí)際的功能只有在構(gòu)造函數(shù)調(diào)用該函數(shù)時(shí)才變得固定。就是在那個(gè)時(shí)候:
func(reveal);
此模式通常用于允許外部代碼限制訪問(wèn)構(gòu)造函數(shù)中的私有函數(shù)卦睹,當(dāng)然畦戒,Promise構(gòu)造函數(shù)允許您訪問(wèn)resolve和reject函數(shù)。
承諾機(jī)制
創(chuàng)建標(biāo)準(zhǔn)Promise時(shí)结序,將使用其構(gòu)造函數(shù)障斋,并向其傳遞一個(gè)函數(shù)executor,該函數(shù)立即由構(gòu)造函數(shù)執(zhí)行徐鹤。此函數(shù)可用于創(chuàng)建異步任務(wù)鸯旁,然后相應(yīng)地調(diào)用resolve或reject-通常在異步任務(wù)完成時(shí)猛蔽。
換句話說(shuō),這是起作用的代碼。
例如脉漏,可以使用JavaScript Promises 延遲函數(shù)示例編寫為:
function delay(t) {
var p = new Promise(
function (resolve, reject) {
setTimeout(
function () {
resolve();
},
t);
});
return p;
}
您可以看到它具有相同的基本結(jié)構(gòu)秩伞,唯一的區(qū)別是現(xiàn)在代碼調(diào)用了在構(gòu)造函數(shù)中定義的專用resolve和reject函數(shù)摄悯。構(gòu)造函數(shù)立即執(zhí)行此操作峡竣,將私有的resolve和reject函數(shù)傳遞給它秸谢,并返回Promise。
請(qǐng)注意霹肝,在傳遞給構(gòu)造函數(shù)的函數(shù)中估蹄,解析和拒絕的調(diào)用導(dǎo)致調(diào)用Promise使用者使用返回的Promise對(duì)象的then方法設(shè)置的所有onComplete和onError函數(shù)。僅在異步任務(wù)完成后才調(diào)用resolve或拒絕阿迈,并在resolve和reject中返回其值或錯(cuò)誤代碼元媚。
現(xiàn)在,我們可以理解上一章中介紹的示范Promise:
function delay(t, p) {
var promise = new Promise(
function (resolve, reject) {
setTimeout(
function () {
var r = Math.random();
if (r > p) {
resolve(r);
} else {
reject(r);
}
},
t);
});
return promise;
}
您可以看到發(fā)生了什么事苗沧,我們創(chuàng)建了一個(gè)新的Promise對(duì)象刊棕,該對(duì)象幾乎立即返回給調(diào)用者。我們還使用setTimeout在事件隊(duì)列上放置一個(gè)函數(shù)待逞,當(dāng)事件時(shí)間到時(shí)甥角,將以指定的概率調(diào)用resolve或reject函數(shù),將隨機(jī)數(shù)作為確定的值傳遞回去识樱。
要100%清除Promise構(gòu)造函數(shù)中使用的resolve和reject函數(shù)嗤无,是構(gòu)造函數(shù)提供的私有函數(shù)。揭示性的構(gòu)造器模式可確保這些值不能被構(gòu)造器或promise之外的任何其他代碼訪問(wèn)怜庸。
摘要
- Promise旨在限制對(duì)解析和拒絕功能的訪問(wèn)当犯,而這些功能只能用于創(chuàng)建Promise的代碼。
- 過(guò)去割疾,這是使用單獨(dú)的延遲對(duì)象(該對(duì)象保持私有狀態(tài))完成的嚎卫。
- Promise標(biāo)準(zhǔn)利用揭示性的構(gòu)造函數(shù)模式來(lái)保持解析和拒絕私有,同時(shí)允許創(chuàng)建Promise的代碼向構(gòu)造函數(shù)提交使用它們的函數(shù)宏榕。
- 揭示性構(gòu)造函數(shù)模式通過(guò)將私有變量傳遞給傳遞給構(gòu)造函數(shù)的函數(shù)拓诸,擴(kuò)展了閉包為構(gòu)造對(duì)象提供私有變量和函數(shù)的方式。