木灵鱼儿

木灵鱼儿

阅读:35

最后更新:2021/10/14/ 11:29:14

深度合并对象的方法

找了很久,现有的库有两个:

1. Merge

npm地址: Merge

用法:

import merge from 'merge';

const obj1 = { name: 2};
const obj2 = { value: 1 };

//合并
merge(obj1,obj2);
console.log(obj1);  //{name:2,value:1}

//克隆合并-与目标对象无关联
const obj3 = merge(true,obj1,obj2);
console.log(obj3);  //{name:2,value:1}
console.log(obj3 === obj1);  //false

//上面两种合并都是类似Object.assgin,只会处理第一层属性,如果需要合并每一个对象的键值,需要使用 recursive方法

//递归合并
const obj4 = {
  level: { str: 'hello world' }
};
const obj5 = {
    level: { value: 1 },    
};

const obj6 = merge.recursive(true,obj4,obj5);
console.log(obj6);
//{level: { str: 'hello world',value: 1 }}

Merge对于对象合并很美好,但是如果对象中存在数组,那么效果就不太行了。

import merge from 'merge';

const obj1 = { arr: [1,2] };
const obj2 = { arr: [3,4] };

merge(obj1,obj2);
console.log(obj1);  //{ arr: [3,4] }

看使用场景使用。

2. deepmerge

npm地址: deepmerge

深度合并相比较Merge,它对数组合并做了处理,支持:concat连接数组,也可以进行替换操作。

替换

const overwriteMerge = (destinationArray, sourceArray, options) => sourceArray

merge(
    [1, 2, 3],
    [3, 2, 1],
    { arrayMerge: overwriteMerge }
) // => [3, 2, 1]

连接

merge(
    [1, 2],
    [3, ],
) // => [1,2,3]

具体我也没怎么用,自行尝试。

3. MuMerge

这个就是我写的,支持对象与对象合并,数组与数组合并,两种合并方式:mergecloneMerge

merge是将数据合并到目标对象target参数,cloneMerge则是合并生成的是一个全新的对象。

代码:

/*
 * @Author: mulingyuer
 * @Date: 2021-10-13 17:58:00
 * @LastEditTime: 2021-10-14 10:18:40
 * @LastEditors: mulingyuer
 * @Description:合并对象
 * @FilePath: \saas-admin-vue\src\base\utils\mu-merge.js
 * 怎么可能会有bug!!!
 */

const MuMerge = {
  //合并
  merge(target, ...source) {
    if (MuMerge.isObject(target)) {
      return MuMerge.objectMerge(target, ...source);
    } else if (MuMerge.isArray(target)) {
      return MuMerge.arrayMerge(target, ...source);
    } else {
      throw new Error("合并target的目标参数不是一个键值对象或者数组");
    }
  },

  //克隆合并-与目标对象无关联
  cloneMerge(target, ...source) {
    if (MuMerge.isObject(target)) {
      return MuMerge.objectMerge({}, target, ...source);
    } else if (MuMerge.isArray(target)) {
      return MuMerge.arrayMerge([], target, ...source);
    } else {
      throw new Error("合并target的目标参数不是一个键值对象或者数组");
    }
  },

  //对象合并
  objectMerge(target, ...source) {
    //校验
    MuMerge.validateObject(target, "合并的目标参数必须是一个键值对象");
    if (!source.length) return target; //没有要合并的参数返回原值
    source.forEach(value => MuMerge.validateObject(value, "被合并的参数必须是一个键值对象"))


    //合并
    source.forEach(value => {
      const valueKeys = MuMerge.getKeys(value);
      valueKeys.forEach(key => {
        const val = value[key];

        if (MuMerge.isObject(val)) { //值为对象

          if (!target[key]) target[key] = {};
          if (MuMerge.isObject(target[key])) {
            target[key] = MuMerge.objectMerge(target[key], val);
          } else {
            target[key] = MuMerge.deepCopy(val);
          }

        } else if (MuMerge.isArray(val)) { //值为数组

          if (!target[key]) target[key] = [];
          if (MuMerge.isArray(target[key])) {
            target[key] = MuMerge.arrayMerge(target[key], val);
          } else {
            target[key] = MuMerge.deepCopy(val);
          }

        } else {
          target[key] = val;
        }
      })
    });

    return target;
  },

  //数组合并
  arrayMerge(target, ...source) {
    //校验
    MuMerge.validateArray(target, "合并的目标对象必须是一个数组对象");
    if (!source.length) return target; //无合并对象,返回
    source.forEach(value => MuMerge.validateArray(value, "被合并的对象必须是一个数组"));


    //合并
    source.forEach(value => {
      value.forEach((item, index) => {

        if (MuMerge.isObject(item)) {

          if (!target[index]) target[index] = {};
          if (MuMerge.isObject(target[index])) {
            target[index] = MuMerge.objectMerge(target[index], item);
          } else {
            target[index] = MuMerge.deepCopy(item);
          }

        } else if (MuMerge.isArray(item)) {

          if (!target[index]) target[index] = [];
          if (MuMerge.isArray(target[index])) {
            target[index] = MuMerge.arrayMerge(target[index], item);
          } else {
            target[index] = MuMerge.deepCopy(item);
          }

        } else {
          target[index] = item;
        }

      });
    });

    return target;
  },

  //深拷贝
  deepCopy(data) {
    if (!MuMerge.isArray(data) && !MuMerge.isObject(data)) return data;

    const weakMap = new WeakMap();

    function copy(data) {

      if (weakMap.has(data)) return null; //打断施法
      const copyData = data instanceof Array ? [] : {};
      weakMap.set(data, true);

      for (let [key, value] of Object.entries(data)) {
        copyData[key] = typeof value === "object" ? copy(value) : value;
      };

      return copyData;
    }

    return copy(data);
  },

  //对象校验
  validateObject(value, message = "") {
    if (!MuMerge.isObject(value)) {
      throw new Error(`${message ? message : '参数必须是一个键值对象'},参数:${value}`)
    }
  },

  //数组校验
  validateArray(value, message = "") {
    if (!MuMerge.isArray(value)) {
      throw new Error(`${message ? message : '参数必须是一个数组对象'},参数:${value}`)
    }
  },

  //获取键数组
  getKeys(value) {
    return Object.keys(value);
  },

  //是否对象
  isObject(value) {
    return MuMerge.getType(value) === "object";
  },

  //是否数组
  isArray(value) {
    return MuMerge.getType(value) === "array";
  },

  //获取数据类型
  getType(value) {
    const type = typeof value;
    if (type !== "object") return type;
    return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
  },

}


const merge = MuMerge.merge;
const cloneMerge = MuMerge.cloneMerge;


export {
  merge,
  cloneMerge,
}
export default merge;

使用:

import MuMerge,{meage,cloneMerge} from "MuMerge";

const obj1 = {value:1};
const obj2 = {value:2};

const obj3 = MuMerge(obj1,obj2); //{value:2};
console.log(obj3===obj1); //true


const obj4 = cloneMerge(obj1,obj2); //{value:2};
console.log(obj4===obj1); //false

MuMerge === meage; //true

版权申明

本文系作者 @木灵鱼儿 原创发布在木灵鱼儿 - 有梦就能远航站点。未经许可,禁止转载。

关于作者

站点职位 博主
获得点赞 0
文章被阅读 35

相关文章