You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何以不可变方式扩展嵌套对象?仅重建变更路径对象

实现嵌套对象的不可变深度扩展(仅重建变更节点)

需求背景

需要对多层嵌套的对象进行不可变扩展:添加或修改属性时,不直接修改原对象,且仅重建发生变更的节点,未变更的节点保持原引用,避免全量重建复杂嵌套对象带来的性能开销。

示例说明

基础对象(base)

{
  foo: {
    bar: {
      baz: 123
    },
    hello: 'world',
    something: {
      deeply: {
        nested: true
      }
    }
  }
}

扩展对象(updates)

{
  foo: {
    hello: 'earth',
    something: {
      deeply: {
        iAmNew: 32134
      }
    }
  }
}

预期结果

{
  foo: {
    bar: {
      baz: 123
    },
    hello: 'earth',
    something: {
      deeply: {
        nested: true,
        iAmNew: 32134
      }
    }
  }
}

注:{baz:123}节点未发生变更,因此不需要重建,保持原对象引用。

现有不完整实现

export function extend(
  start,
  updates,
) {
  const end = { ...start }

  let node = end

  for (const i in updates) {
    const val = updates[i]
    if (val != null) {
      if (typeof val === 'object') {
      }
    }
  }

  return end
}

完整实现方案

通过递归处理嵌套对象,仅在需要变更的层级创建新对象,未变更的层级直接复用原引用:

export function extend(start, updates) {
  // 若扩展对象无效,直接返回原对象
  if (!updates || typeof updates !== 'object') {
    return start;
  }

  // 创建当前层级的新对象,复制原对象所有属性
  const end = { ...start };

  for (const key in updates) {
    const updateVal = updates[key];
    if (updateVal == null) {
      // 处理 null/undefined 类型的更新值
      end[key] = updateVal;
      continue;
    }

    const startVal = start[key];
    // 仅当两边都是纯对象(非数组)时,递归处理嵌套层级
    if (typeof updateVal === 'object' && typeof startVal === 'object' && 
        !Array.isArray(updateVal) && !Array.isArray(startVal)) {
      // 递归扩展嵌套对象,仅重建有变更的子节点
      end[key] = extend(startVal, updateVal);
    } else {
      // 非对象类型直接赋值(覆盖或新增属性)
      end[key] = updateVal;
    }
  }

  return end;
}

逻辑说明

  1. 边界处理:如果传入的扩展对象无效(非对象或为空),直接返回原对象,避免不必要的操作。
  2. 当前层级复用与重建:创建当前层级的新对象,复制原对象的所有属性,但只有当子节点发生变更时,才会对该子节点进行重建。
  3. 递归处理嵌套:当原对象和扩展对象的对应属性都是纯对象时,递归调用extend函数处理嵌套层级,确保仅重建有变更的子节点。
  4. 直接赋值场景:对于非对象类型(如字符串、数字)或数组,直接赋值覆盖或新增属性。

验证示例

const base = {
  foo: {
    bar: { baz: 123 },
    hello: 'world',
    something: { deeply: { nested: true } }
  }
};

const updates = {
  foo: {
    hello: 'earth',
    something: { deeply: { iAmNew: 32134 } }
  }
};

const result = extend(base, updates);

// 验证未变更节点的引用一致性
console.log(result.foo.bar === base.foo.bar); // 输出 true,说明{baz:123}未被重建
console.log(result.foo.something.deeply.nested); // 输出 true,保留原属性
console.log(result.foo.something.deeply.iAmNew); // 输出 32134,新增属性
console.log(result.foo.hello); // 输出 'earth',覆盖属性

内容的提问来源于stack exchange,提问作者Lance Pollard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 19:13:25