object.assign() 返回目标对象,天然支持链式调用;需以可变普通对象为起点,避免冻结/原始值,配合 inject 函数可实现流畅属性注入。

Object.assign() 本身返回目标对象(即第一个参数),这个特性天然支持链式调用——你不需要额外包装,只要确保每次操作都以可变对象为起点,就能连续注入属性。
核心思路:始终让目标对象是可变的引用
链式调用的前提是每一步都返回同一个对象实例(而非新对象)。Object.assign() 正好满足这点:它把源对象的自有可枚举属性复制到目标对象上,并返回该目标对象。
- 目标对象必须是普通对象(如
{}或已有对象),不能是null、undefined或原始值 - 避免传入冻结/密封对象(
Object.freeze()等),否则赋值会静默失败 - 推荐从空对象起步,作为“注入容器”:
Object.assign({}, ...)返回新对象,不链式;而Object.assign(target, ...)才链式
简易链式注入器实现
无需类或复杂封装,一个纯函数即可:
const inject = (target) => ({
with: (source) => {
Object.assign(target, source);
return { with, done: () => target };
},
done: () => target
});
用法示例:
const user = inject({})
.with({ name: 'Alice' })
.with({ age: 30 })
.with({ role: 'admin' })
.done();
// → { name: 'Alice', age: 30, role: 'admin' }
关键点:每次 .with() 都复用同一个 target,Object.assign 直接修改它并返回自身,保持链路畅通。
进阶:支持深合并与条件注入
Object.assign() 是浅拷贝,若需嵌套属性注入,可组合工具函数:
- 用
lodash.merge替代Object.assign实现深合并(注意它也返回目标对象,仍可链式) - 添加
when(predicate, source)方法:仅当条件为真时才注入,保持链式结构不变 - 加入
omit(keys)或pick(keys),在注入后筛选最终属性
例如:
const config = inject({ host: 'localhost' })
.with({ port: 3000 })
.when(process.env.NODE_ENV === 'prod', { ssl: true })
.done();
注意事项与边界
链式注入器简洁高效,但要注意:
- 所有注入都是**可变操作**——原始
target被持续修改,不适合需要不可变语义的场景 - 同名属性会被后续调用覆盖,顺序即优先级
- 无法处理 getter/setter、不可枚举属性、Symbol 键(Object.assign 只处理自有可枚举字符串键)
- 若需不可变链式,应改用
{...target, ...source}展开语法 + 函数式组合,但此时每次返回新对象,严格意义上不算“同一对象链式”
本质上,这是对原生 API 的轻量适配——利用它的返回值契约,把“注入”变成流畅的声明式表达。










