登录
首页 >  文章 >  前端

Object.assign 多级对象合并技巧

时间:2026-05-20 13:15:14 427浏览 收藏

本文深入解析了JavaScript中Object.assign在多级对象合并时的局限性——它仅执行浅拷贝,导致嵌套对象被完全覆盖而非递归合并,并手把手带你实现安全可靠的deepAssign函数,涵盖null、数组、日期及__proto__等关键边界处理;同时推荐现代环境下的structuredClone+递归方案提升安全性与不可变性,最后指出复杂场景下应优先选用lodash.merge等成熟库,避免自行实现埋下原型污染或类型误判等隐患。

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

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}}

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

  • Object.assign 只复制可枚举自有属性,但你的配置对象若来自 Object.create(null) 或带自定义 toString 等方法,可能漏掉关键字段
  • 如果源对象有 __proto__constructor 字段(尤其从 JSON 解析或用户输入来),直接合并可能触发原型链污染 —— 建议在递归前过滤掉这些危险键名
  • 别把 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,自己手写容易漏边界条件。

今天关于《Object.assign 多级对象合并技巧》的内容就介绍到这里了,是不是学起来一目了然!想要了解更多关于的内容请关注golang学习网公众号!

资料下载
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>