下面的代码示例展示了如何构建一个代理层次结构,模拟类和子类。它通过使用多个代理对象包装标准对象并巧妙地使用处理程序 get 选项来实现这一点。
代理的处理程序是
混入模式的一种形式。我们可以使用混入模式来模拟子类化。
代码包含两种类型的代理“类”:EmitterBase 和 EmitterNet。它们用于收集特定于 vanilla EventEmitter 或其子类 Net 的统计信息。EmitterNet 不会复制 EmitterBase 的功能,而是通过包装 EmitterBase 来重用它。请注意,在示例中,我们包装了 http.Server:Net 的子类和 EventEmitter 的子子类。
传递给代理的处理程序实现了子类代理的所有行为。多个处理程序版本实现子类。例如,在
EmitterBase
中,我们收集对
on
和
emit
的调用统计信息(计算调用次数)。
EmitterBase
还实现幻影成员和方法来跟踪和报告这些计数。这相当于具有这些方法和成员的基类。请参见
wrapEmitterBase
中的
handler
。
接下来,我们使用另一个处理程序(请参见wrapEmitterNet
)创建代理“子类”,该处理程序实现了两个新的幻影成员来计算Net特定调用(listen
和close
)。它还实现了一个stats()
方法,该方法覆盖了来自基类的方法以及调用被覆盖的方法。
代理标准为我们提供了足够的功能,以实现代理子类化,而无需诉诸于类包装器并搞乱this
。
import * as util from 'node:util';
import http from 'node:http';
import { EventEmitter } from 'node:events';
async function DemoProxyHierarchy()
{
const greeter = wrapEmitterBase(new EventEmitter());
greeter.on("hello", (person) => console.log((`Hello, ${person}!`)));
greeter.emit("hello", "World");
greeter.emit("hello", "Benjamin");
console.log(`on calls: ${greeter.countOn}`);
console.log(`emit calls: ${greeter.countEmit}`);
console.log(`statistics: ${JSON.stringify(greeter.stats())}`);
const stats = new Promise((Resolve, reject) => {
let steps = 0;
const server = http.createServer((req, res) => { res.end() });
const netWrapper = wrapEmitterNet(server) as any;
const done = () => {
if (++steps > 2) {
console.log(`\non calls: ${netWrapper.countOn}`);
console.log(`emit calls: ${netWrapper.countEmit}`);
netWrapper.close(() => Resolve(netWrapper.stats()));
}
};
netWrapper.listen(8080, done);
http.get('http://localhost:8080', done);
http.get('http://localhost:8080', done);
});
return stats.then(s => console.log(`net stats: ${JSON.stringify(s)}`));
}
function wrapEmitterBase(ee: EventEmitter)
{
const stats = { on: 0, emit: 0 };
const handler = {
get: (target, key) => {
switch (key) {
case "countOn": return stats.on;
case "countEmit": return stats.emit;
case "stats": return () => ({ ...stats });
case "on": { stats.on++; break; }
case "emit": { stats.emit++; break; }
}
return target[key];
},
}
return new Proxy(ee, handler);
}
function wrapEmitterNet(ee: EventEmitter)
{
const stats = { listen: 0, close: 0 };
const handler = {
get: (target, key) => {
switch (key) {
case "stats": {
return () => ({ ...target[key](), ...stats });
}
case "listen": { stats.listen++; break; }
case "close": { stats.close++; break; }
}
return target[key];
},
};
return new Proxy(wrapEmitterBase(ee), handler);
}
(()=> { await DemoProxyHierarchy() })();
receiver
被描述为“要么是代理,要么是继承自代理的对象”。这听起来好像Proxy
应该是可扩展的。我记得在规范中看到过类似的评论,但现在找不到了。这似乎与观察结果相矛盾... - Sebastian