如何在构造时最优传递并合并子类型专属参数至父类?
问题描述
我有一个名为Rule的主类,它包含param属性,并有多个子类示例如下:
class Rule { param = {} constructor (param) { // 这里我想添加逻辑,融合子类的this.param和构造函数传入的param参数 } } class SubRule1 extends Rule { param = { subparam: { values: ['A', 'B', 'C'], value: 'A' } } constructor (param) { super(param) } } class SubRule2 extends Rule { param = { subparam: { values: [1, 2], value: 1 } } constructor (param) { super(param) } } let myrule = new SubRule1({ subparam: 'B' }) >> 期望结果 Object { subparam: { values: ['A', 'B', 'C'], value: 'B' }} let myrule2 = new SubRule2({ subparam: 2 }) >> 期望结果 Object { subparam: { values: [1, 2], value: 2 }}
实例化新对象时,我希望为所有子类融合this.param与构造函数传入的param参数。我原本想在Rule类中添加该逻辑,但在Rule.constructor中访问this.param时,获取的是Rule类中定义的属性而非子类的this.param。请问采用何种设计才能正确初始化所有子类的this.param?
解决方案
问题的核心在于类字段初始化的执行顺序:子类的param类字段是在super()执行完毕之后才会赋值的,所以父类Rule的构造函数里直接访问this.param拿到的是父类自己的初始值。
下面提供几种可行的解决方法:
方法1:利用微任务延迟执行融合逻辑
通过queueMicrotask延迟执行合并逻辑,确保子类的param已经完成初始化:
class Rule { param = {} constructor(param) { queueMicrotask(() => { this.param = this.mergeParams(this.param, param); }); } // 封装通用的参数合并方法,可根据实际需求扩展深层合并逻辑 mergeParams(base, override) { if (override.subparam != null) { return { ...base, subparam: { ...base.subparam, value: override.subparam } }; } return { ...base, ...override }; } } // 子类代码无需修改 class SubRule1 extends Rule { param = { subparam: { values: ['A', 'B', 'C'], value: 'A' } } constructor(param) { super(param); } } class SubRule2 extends Rule { param = { subparam: { values: [1, 2], value: 1 } } constructor(param) { super(param); } } let myrule = new SubRule1({ subparam: 'B' }); console.log(myrule.param); // 输出 { subparam: { values: ['A','B','C'], value: 'B' }} let myrule2 = new SubRule2({ subparam: 2 }); console.log(myrule2.param); // 输出 { subparam: { values: [1,2], value: 2 }}
方法2:使用静态属性存储子类默认参数(推荐)
将子类的默认param定义为静态属性,父类构造函数直接读取该静态属性完成合并,逻辑同步且清晰:
class Rule { constructor(param) { // 读取子类的静态defaultParam,默认值为空对象 const baseParam = this.constructor.defaultParam || {}; this.param = this.mergeParams(baseParam, param); } mergeParams(base, override) { if (override.subparam != null) { return { ...base, subparam: { ...base.subparam, value: override.subparam } }; } return { ...base, ...override }; } } class SubRule1 extends Rule { static defaultParam = { subparam: { values: ['A', 'B', 'C'], value: 'A' } } constructor(param) { super(param); } } class SubRule2 extends Rule { static defaultParam = { subparam: { values: [1, 2], value: 1 } } constructor(param) { super(param); } } let myrule = new SubRule1({ subparam: 'B' }); console.log(myrule.param); // 符合期望结果 let myrule2 = new SubRule2({ subparam: 2 }); console.log(myrule2.param); // 符合期望结果
方法3:子类构造函数主动触发合并
让子类在super()执行完毕后,手动调用父类的合并方法,完成参数融合:
class Rule { param = {} constructor(param) { this._overrideParam = param; } mergeParams(base) { const override = this._overrideParam; if (override.subparam != null) { this.param = { ...base, subparam: { ...base.subparam, value: override.subparam } }; } else { this.param = { ...base, ...override }; } } } class SubRule1 extends Rule { param = { subparam: { values: ['A', 'B', 'C'], value: 'A' } } constructor(param) { super(param); this.mergeParams(this.param); } } class SubRule2 extends Rule { param = { subparam: { values: [1, 2], value: 1 } } constructor(param) { super(param); this.mergeParams(this.param); } }
三种方法中,方法2的实现最简洁可靠,没有异步延迟的潜在问题,也能统一管理子类的默认参数。
内容的提问来源于stack exchange,提问作者user1595929
相关产品推荐
相关产品推荐

