基于当前实例创建修改部分属性新实例的方法命名规范咨询
不可变对象更新方法的命名规范与优化方案
一、通用命名规范
这类基于当前实例创建新实例、保留原有属性默认值并修改指定属性的方法,业界有不少通用命名方式,常见的包括:
copyWith:语义最清晰,直接表达“复制当前实例并修改部分属性”的意图,在Flutter、TypeScript等生态中广泛使用。with:如果是针对单个属性的方法会写成withAKey,通用型方法直接用with作为名称也很常见,传递键值对参数即可。cloneWith:和copyWith语义接近,强调“克隆+修改”的组合动作,适合对“复制”动作更强调的场景。update:注意这个名称容易被误解为修改当前实例(突变),如果使用必须在注释或文档里明确说明是返回新实例,不修改原对象。
二、避免对象突变的优化方案
1. 用对象展开语法简化代码
JavaScript的对象展开运算符可以简化属性合并逻辑,同时处理undefined参数的问题:
class MyNode { constructor({aKey, bKey}) { this.aKey = aKey ?? 0; this.bKey = bKey ?? 0; } copyWith({aKey, bKey} = {}) { // 过滤掉undefined的参数,避免覆盖原有属性 const updates = {}; if (aKey !== undefined) updates.aKey = aKey; if (bKey !== undefined) updates.bKey = bKey; return new MyNode({...this, ...updates}); } }
或者用更简洁的过滤写法:
copyWith(updates = {}) { const validUpdates = Object.fromEntries( Object.entries(updates).filter(([_, val]) => val !== undefined) ); return new MyNode({...this, ...validUpdates}); }
2. 封装通用更新逻辑
如果多个类需要这类功能,可以用混入(mixin)封装通用逻辑,避免重复代码:
// 通用copyWith混入 function CopyWithMixin(Base) { return class extends Base { copyWith(updates = {}) { const validUpdates = Object.fromEntries( Object.entries(updates).filter(([_, val]) => val !== undefined) ); return new this.constructor({...this, ...validUpdates}); } }; } // 应用到MyNode类 class MyNode extends CopyWithMixin(class { constructor({aKey, bKey}) { this.aKey = aKey ?? 0; this.bKey = bKey ?? 0; } }) {}
3. 借助不可变数据库
如果项目中有大量不可变对象操作,使用Immer这类库可以大幅简化代码,它允许你用“看起来像突变”的写法,底层自动生成新实例:
import {produce} from 'immer'; class MyNode { constructor({aKey, bKey}) { this.aKey = aKey ?? 0; this.bKey = bKey ?? 0; } copyWith(updates) { return produce(this, draft => { // 这里的draft是临时代理,修改它不会影响原实例 Object.assign(draft, updates); }); } }
内容的提问来源于stack exchange,提问作者Rax Adaam
相关产品推荐
相关产品推荐

