Object.assign 和展开运算符无绝对优劣,关键看场景:展开运算符语法更直观简洁、支持混合声明;Object.assign 更适配动态参数、兼容老环境、对 null/undefined 更宽容;意图上,创建新对象推荐展开,复用更新已有对象则用 Object.assign。

Object.assign 和展开运算符({...obj})在语法层面没有绝对优劣,关键看具体场景——前者更强调“动作”与兼容性,后者更突出“结构”与表达力。
语法清晰度:展开运算符更直观
展开运算符直接嵌入对象字面量中,语义贴近自然语言:“把这几个对象的属性摊开、合在一起”。
- 写法简洁:{ defaults, userOptions } 比 Object.assign({}, defaults, userOptions) 少写括号、逗号和重复关键词
- 顺序即逻辑:属性出现顺序天然体现覆盖优先级,无需记忆“从左到右还是右到左”
- 支持混合声明:可同时写静态字段、计算属性、解构赋值,比如 { ...defaults, id: 123, ...userOptions, updatedAt: Date.now() }
语法灵活性:Object.assign 更适配动态参数
当源对象数量不确定或来自变量数组时,Object.assign 可直接传入展开的参数列表,而展开运算符无法原生支持。
- 动态合并多对象:const sources = [a, b, c, d]; Object.assign({}, ...sources) 可行;{ ...sources } 则报错(sources 是数组,不是对象)
- 函数式组合友好:可配合 apply 或 rest 参数封装工具函数,如 const merge = (...objs) => Object.assign({}, ...objs)
- 老环境无转换成本:不依赖 Babel 转译即可运行(IE 不支持展开运算符,但支持 Object.assign)
语法安全性:两者处理空值方式不同
语法本身不报错,但行为差异会影响代码健壮性。
立即学习“Java免费学习笔记(深入)”;
- null/undefined 源对象:Object.assign 会跳过;展开运算符会直接抛 TypeError —— 这不是语法缺陷,而是类型约束更严格
- 防御写法成本不同:用展开需手动保护,如 { ...(defaults || {}), ...(userOptions || {}) };Object.assign 默认宽容
- 错误定位更明确:展开运算符在解构阶段失败,堆栈指向更精准;Object.assign 的静默跳过可能掩盖配置缺失问题
语法意图表达:目标是否复用决定选型
语法选择应反映开发者的真实意图,而非单纯追求简短。
- 创建新对象:两者等价,展开运算符更轻量,推荐
- 复用并更新已有对象:Object.assign(target, update) 语义明确;展开无法就地修改,强行模拟({ ...target, ...update })本质是替换引用,逻辑不同
- 配置合并场景:展开写法 { ...defaults, ...userOptions } 更易读;但若 userOptions 可能为空,Object.assign 更省心


















