Skip to content

devDeepMerge 合并两个对象

递归合并两个对象,生成新的对象,且不会修改原始对象, 并根据特定层次或全局的过滤规则过滤指定的属性。 同时,当 obj2 的属性值为 undefined 或 null 时,跳过合并该属性。 过滤逻辑同时作用于 obj1 和 obj2 中的属性。

使用示例

ts
import {devDeepMerge} from 'devecoui-plus'; 

// 示例对象
const obj1 = {
  name: 'Alice',
  age: 25,
  address: {
    city: 'New York',
    zip: '10001',
  },
  preferences: {
    theme: 'dark',
    notifications: true,
  }
};

const obj2 = {
  age: 30, // 覆盖 age
  address: {
    zip: '10002', // 覆盖 zip
    street: '5th Avenue',
  },
  preferences: {
    notifications: false, // 覆盖 notifications
  },
  occupation: 'Engineer', // 新增属性
};

// 过滤规则
const filterRules = {
  _all: ['occupation'], // 在所有层级中过滤掉 occupation
  address: {
    street: true, // 在 address 层级中过滤 street 属性
  }
};

// 调用 devDeepMerge
const mergedResult = devDeepMerge(obj1, obj2, filterRules);

console.log(mergedResult);

/**
 * 输出
 * {
 *   "name": "Alice",
 *   "age": 30,
 *   "address": {
 *     "city": "New York",
 *     "zip": "10002"
 *   },
 *   "preferences": {
 *     "theme": "dark",
 *     "notifications": false
 *   }
 * }
 */

方法源码

ts
/**
 * 递归合并两个对象,生成新的对象,且不会修改原始对象,
 * 并根据特定层次或全局的过滤规则过滤指定的属性。
 * 同时,当 obj2 的属性值为 undefined 或 null 时,跳过合并该属性。
 * 过滤逻辑同时作用于 obj1 和 obj2 中的属性。
 *
 * @param obj1 - 第一个对象,作为合并基准对象
 * @param obj2 - 第二个对象,用于覆盖第一个对象的值
 * @param filterRules - 可选的过滤规则对象,可以指定某一层要过滤的属性,也可以通过 "_all" 全局过滤所有层级的特定属性
 * @returns 返回合并后的新对象
 */
export function devDeepMerge<T extends Record<string, any>, U extends Record<string, any>>(
    obj1: T,
    obj2: U,
    filterRules: Record<string, any> = {}
): T & U {
    const result = { ...obj1 }; // 复制 obj1,创建新对象,避免修改原始数据

    for (const key in obj2) {
        if (obj2.hasOwnProperty(key)) {
            const value = obj2[key];

            // 跳过 undefined 和 null 的值
            if (value === undefined || value === null) {
                continue;
            }

            // 处理全局过滤:检查是否需要在所有层级中过滤某些字段
            if (filterRules["_all"] && filterRules["_all"].includes(key)) {
                continue; // 跳过全局过滤的字段
            }

            // 处理局部层级过滤:检查当前层级是否有指定的过滤规则
            if (filterRules.hasOwnProperty(key)) {
                if (filterRules[key] === true) {
                    continue; // 跳过局部过滤的字段
                }
                if (devIsObject(filterRules[key]) && devIsObject(value) && devIsObject(obj1[key])) {
                    result[key] = devDeepMerge(obj1[key], value, filterRules[key]) as any;
                    continue;
                }
            }

            // 如果两个都是对象,递归合并
            if (devIsObject(obj1[key]) && devIsObject(value)) {
                result[key] = devDeepMerge(obj1[key], value, filterRules[key] || {}) as any;
            } else {
                // 直接覆盖 result 的值,而不是 obj1
                result[key] = value;
            }
        }
    }

    // 检查并处理 obj1 中的过滤字段
    for (const key in obj1) {
        if (obj1.hasOwnProperty(key)) {
            // 处理全局过滤:检查是否需要在所有层级中过滤某些字段
            if (filterRules["_all"] && filterRules["_all"].includes(key)) {
                delete result[key]; // 从结果中删除全局过滤的字段
            }

            // 处理局部层级过滤:检查当前层级是否有指定的过滤规则
            if (filterRules.hasOwnProperty(key)) {
                if (filterRules[key] === true) {
                    delete result[key]; // 从结果中删除局部过滤的字段
                }
            }
        }
    }

    return result as T & U;
}