如何实现可返回多个装饰器的装饰器工厂,构建可调节组件?
如何让装饰器工厂返回多个装饰器并批量应用?
问题描述
我想用装饰器(插件系统)构建高度可定制的组件,找到了一个基于装饰器工厂的方案,但它只能返回单个装饰器。
原方案示例:
function AorB() { // 只能返回单个装饰器 return condition ? DecoratorA : DecoratorB; }
class SampleClass { @AorB() sampleField; }
我想要实现的效果是让装饰器工厂返回任意数量的装饰器,像这样:
function Plugin() { // 返回任意数量的装饰器 return [ DecoratorA, DecoratorB, //... 更多装饰器 ] }
// 类似这样批量应用 ...@Plugin() class SampleClass { sampleField; }
请问有没有办法实现这个需求?
可行实现方案
JavaScript/TypeScript的装饰器语法本身不支持直接返回装饰器数组并批量应用,但可以通过包装多个装饰器为一个复合装饰器的方式实现类似效果。
方法1:通用装饰器组合函数
先实现一个可复用的工具函数,把多个装饰器按预期顺序组合成单个装饰器:
// 适用于属性、方法、访问器装饰器 function composeDecorators(...decorators) { return function(target, propertyKey, descriptor) { // 倒序执行装饰器,保证和手动写多个@的顺序一致 for (const decorator of decorators.reverse()) { descriptor = decorator(target, propertyKey, descriptor) || descriptor; } return descriptor; }; }
修改你的Plugin工厂函数,用这个组合函数打包装饰器数组:
function Plugin() { // 按需收集要应用的装饰器 const pluginDecorators = [DecoratorA, DecoratorB]; return composeDecorators(...pluginDecorators); }
之后正常使用即可,效果等同于手动添加多个装饰器:
class SampleClass { @Plugin() sampleField; }
方法2:工厂函数内直接批量执行
如果不需要复用组合逻辑,可以直接在Plugin工厂里处理装饰器批量应用:
function Plugin() { return function(target, propertyKey, descriptor) { // 定义要应用的装饰器列表 const decorators = [DecoratorA, DecoratorB]; // 倒序遍历执行,保证顺序正确 for (const dec of decorators.reverse()) { const newDescriptor = dec(target, propertyKey, descriptor); if (newDescriptor) descriptor = newDescriptor; } return descriptor; }; }
注意事项
- 装饰器顺序:因为装饰器的执行逻辑是从后往前堆叠的,所以必须用
reverse()遍历数组,才能让数组中第一个装饰器的作用顺序和手动写@DecoratorA、@DecoratorB一致。 - 适配不同装饰器类型:上面的示例针对的是属性/方法装饰器,如果是类装饰器,需要调整组合函数的参数:
// 适用于类装饰器的组合函数 function composeClassDecorators(...decorators) { return function(target) { for (const decorator of decorators.reverse()) { target = decorator(target) || target; } return target; }; }
内容的提问来源于stack exchange,提问作者Fel AA
相关产品推荐
相关产品推荐

