本文为翻译:
https://www.i-programmer.info/programming/javascript/11379-javascript-async-promises-the-revealing-constructor-pattern.html
概念解析:
revealing-constructor pattern
揭示性的建构模式
Promise 对构造函数提供私有方法(显示构造函数模式)的标准方式进行了修改。
私有方法是在创建对象时作为闭包创建的方法。这是用于创建可从对象内部而不是外部访问的私有变量的标准方法。唯一的区别是变量引用了一个函数。如:
function myConstructor(){
var private=0;
this.myFunction=function(){
alert(private);
}
}
这是仅使用一种方法myFunction的对象的构造函数。
重要的部分是称为private的变量。这不是对象的一部分,因为它没有声明为对象的属性。因此,如果您尝试:
var myObject=new myConstructor(); myObject.private=1;
您将看到一个不存在 private 的错误。但是,由于在声明 myFunction 时在范围内是private,因此可以将其作为闭包使用:
myObject.myFunction();
确实显示private的值。
私有方法使用相同的机制,所不同的是变量引用了一个函数-一个内部函数,该内部函数不是正在构造的对象的方法。
这是JavaScript Promise用来解析和拒绝私有方法的机制,但有一些其他的变化。
私有函数和变量由传递给构造函数的函数访问。
让我们看看它是如何工作的。
假设您需要将私有变量设置为某个值,但仅在使用构造函数时才需要。
最简单的解决方案是:
function myClass(value){
var myPrivateVar=value;
this.myMethod=function(){
console.log(myPrivateVar);
}
}
现在,您可以使用以下方法创建实例:
var myObject=new myClass(10);
myObject.myMethod();
将打印私有变量的值,即10,并且在使用构造函数时已设置了该变量,但是该变量现在无法通过对象外部的代码进行更改。
这似乎很简单,但是如果我们进一步推动这个想法,就会变得更加困难。
如果要在构造函数调用中传递与正在构造的对象的私有成员一起使用的函数,会发生什么情况?该函数旨在由构造函数在创建对象时执行。
第一次尝试可能是这样的:
function myClass(func) {
var myPrivateVar = Math.random();
var reveal = function (){
return myPrivateVar;
}
func();
}
这将创建一个设置为随机值的私有变量,可以通过访问私有方法揭示来发现该私有变量。想法是func是一个传递给构造函数然后执行的函数,可以利用reveal访问该值。
如果通过传递给它一个尝试利用揭示的函数来进行尝试:
var myObject = new myClass(
function () { console.log(reveal()); }
);
当调用 func 时,您将看到一条错误消息,提示 reveal 未定义。
这里的错误是显而易见的,表明不在传递给构造函数的函数范围内。函数可以访问哪些变量取决于函数的声明位置,而不是使用位置。解决该错误的方法非常简单–将所需的私有成员作为参数传递给函数。
就是:
var myObject = new myClass(
function (reveal) { console.log(reveal()); }
);
现在注意,该函数需要在构造函数中使用参数进行调用:
function myClass(func) {
var myPrivateVar = Math.random();
var reveal = function () { return myPrivateVar;};
func(reveal);
}
现在一切正常。传递给构造函数的函数可以调用私有函数,只要它们在调用函数时传递给私有函数即可。
一般原则是:
- 对象的构造函数中的局部变量以及内部函数是该构造函数及其构造的对象的私有属性。
- 对象可以通过闭包访问这些私有变量。
- 通过传递参数调用构造函数的代码可以访问私有成员。
- 如果调用构造函数的代码传递了由构造函数执行的函数,则此函数将无法访问私有变量,因为定义函数时它们不在范围内。
- 但是,可以在构造函数调用函数时将私有变量传递给函数,因为它们在作用域内。
注意,您也可以这样写:
var myObject = new myClass(
function (privateFunction) {
console.log(privateFunction());
}
);
该函数的名称只是第一个参数传递的占位符。该函数实际的功能只有在构造函数调用该函数时才变得固定。就是在那个时候:
func(reveal);
此模式通常用于允许外部代码限制访问构造函数中的私有函数,当然,Promise构造函数允许您访问resolve和reject函数。
承诺机制
创建标准Promise时,将使用其构造函数,并向其传递一个函数executor,该函数立即由构造函数执行。此函数可用于创建异步任务,然后相应地调用resolve或reject-通常在异步任务完成时。
换句话说,这是起作用的代码。
例如,可以使用JavaScript Promises 延迟函数示例编写为:
function delay(t) {
var p = new Promise(
function (resolve, reject) {
setTimeout(
function () {
resolve();
},
t);
});
return p;
}
您可以看到它具有相同的基本结构,唯一的区别是现在代码调用了在构造函数中定义的专用resolve和reject函数。构造函数立即执行此操作,将私有的resolve和reject函数传递给它,并返回Promise。
请注意,在传递给构造函数的函数中,解析和拒绝的调用导致调用Promise使用者使用返回的Promise对象的then方法设置的所有onComplete和onError函数。仅在异步任务完成后才调用resolve或拒绝,并在resolve和reject中返回其值或错误代码。
现在,我们可以理解上一章中介绍的示范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;
}
您可以看到发生了什么事,我们创建了一个新的Promise对象,该对象几乎立即返回给调用者。我们还使用setTimeout在事件队列上放置一个函数,当事件时间到时,将以指定的概率调用resolve或reject函数,将随机数作为确定的值传递回去。
要100%清除Promise构造函数中使用的resolve和reject函数,是构造函数提供的私有函数。揭示性的构造器模式可确保这些值不能被构造器或promise之外的任何其他代码访问。
摘要
- Promise旨在限制对解析和拒绝功能的访问,而这些功能只能用于创建Promise的代码。
- 过去,这是使用单独的延迟对象(该对象保持私有状态)完成的。
- Promise标准利用揭示性的构造函数模式来保持解析和拒绝私有,同时允许创建Promise的代码向构造函数提交使用它们的函数。
- 揭示性构造函数模式通过将私有变量传递给传递给构造函数的函数,扩展了闭包为构造对象提供私有变量和函数的方式。