一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

如何用 Object.assign 实现简单的多级配置对象合并

时间:2026-08-07 07:22:48 编辑:袖梨 来源:一聚教程网

处理如何用 Object.assign 实现简单的多级配置对象合并这类问题时,先确认目标场景,再按步骤核对配置或玩法细节。

Object.assign仅浅拷贝,多级对象会覆盖而非递归合并;需手写deepAssign实现深层合并,注意过滤null、数组、日期及__proto__等危险键;现代环境可用structuredClone+递归提升安全性。

Object.assign 不能直接处理多级嵌套合并

它只会做浅拷贝,遇到对象属性时直接覆盖而非递归合并。比如 Object.assign({a: {x: 1}}, {a: {y: 2}}) 结果是 {a: {y: 2}}x 丢了。这不是配置合并想要的行为——你通常希望 a.xa.y 同时保留。

用 Object.assign + 手动递归实现基础多级合并

可以封装一个 deepAssign 函数,在遇到同为对象的属性时递归调用自身,其他情况交给 Object.assign 处理。注意要跳过 null、数组、日期等非 plain object 类型:

function deepAssign(target, ...sources) {  sources.forEach(source => {    if (source == null) return;    Object.keys(source).forEach(key => {      const targetVal = target[key];      const sourceVal = source[key];      if (        targetVal != null &&        typeof targetVal === 'object' &&        sourceVal != null &&        typeof sourceVal === 'object' &&        !Array.isArray(targetVal) &&        !Array.isArray(sourceVal)      ) {        deepAssign(targetVal, sourceVal);      } else {        target[key] = sourceVal;      }    });  });  return target;}

使用示例:deepAssign({}, {db: {host: 'localhost', port: 5432}}, {db: {port: 5433, ssl: true}}){db: {host: 'localhost', port: 5433, ssl: true}}

常见坑:原型链污染与不可枚举属性

  1. Object.assign 只复制可枚举自有属性,但你的配置对象若来自 Object.create(null) 或带自定义 toString 等方法,可能漏掉关键字段
  2. 如果源对象有 __proto__constructor 字段(尤其从 JSON 解析或用户输入来),直接合并可能触发原型链污染 —— 建议在递归前过滤掉这些危险键名
  3. 别把 DateRegExp 当普通对象递归,它们的 typeof 也是 'object',但没 keys 可遍历,会报错

更稳妥的替代方案:用 structuredClone + 自定义逻辑

现代环境(Chrome 98+、Node.js 17+)可用 structuredClone 先深拷贝目标,再逐层 Object.assign,避免修改原对象;但要注意它不支持函数、undefined、循环引用。对于配置合并这类纯数据场景够用:

function safeDeepMerge(target, ...sources) {  const result = structuredClone(target);  sources.forEach(src => {    Object.keys(src).forEach(key => {      const t = result[key];      const s = src[key];      if (t && s && typeof t === 'object' && typeof s === 'object' && !Array.isArray(t) && !Array.isArray(s)) {        result[key] = safeDeepMerge(t, s);      } else {        result[key] = s;      }    });  });  return result;}

真正复杂配置(如含函数、Symbol、特殊类实例)建议用专门库如 lodash.merge,自己手写容易漏边界条件。

热门栏目