木灵鱼儿
阅读:881
深度合并对象的方法
找了很久,现有的库有两个:
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
这个就是我写的,支持对象与对象合并,数组与数组合并,两种合并方式:merge
、cloneMerge
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
版权申明
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿 - 有梦就能远航站点。未经许可,禁止转载。
相关推荐
Promise失败重试,可指定重试次数
//模拟异步请求 function axiosFn() { return new Promise((resolve, reject) => { const flge = Math.random(); //随机值 setTimeout(() => { //大于0.7就是成功 if (flge > 0.7) { return resolve(flge); } else { return reject(...
animation 动画的三个事件
const div = document.querySelector("div.box"); div.addEventListener("animationstart", function() { //动画开始运行触发 }); div.addEventListener("animationiteration", function() { //动画每执行一次触发一次,适用用多次动画 }); div.addEventListener("animationend", function() { //...
手写Promise
/* * @Author: mulingyuer * @Date: 2021-12-30 22:06:58 * @LastEditTime: 2022-01-03 05:22:30 * @LastEditors: mulingyuer * @Description: 手写promise * @FilePath: \undefinedc:\Users\13219\Desktop\promise.js * 怎么可能会有bug!!! */ /** * @description: 自定义promise * @param {fucntion} executor 执行器函数(同...
利用JSON过滤对象和数组中指定的key属性
有时候我们在vue中进行for循环,就会涉及到绑定唯一值key的问题,但是并不是任何时候都会存在所谓的唯一值,使用index下标明显是不合适的,官方也不推荐,除非你for循环出来的列表不用变化。所以一般常用的做法就是给for循环的对象添加一个属性,属性的值是随机的uuid或者时间戳。这样前端问题解决了,如果遍历的数据还需要提交到后端,那么不就多了一个属性,这个属性后端不需要的。所以,我们需要在提交数据前,对数据进行过滤。过滤又得for循环删除?那怎么行,有没有那种通用的,简单的方法。过滤方法/** * @description: 过滤对象中指定的属性,也可以拿来浅拷贝 * @para...
Copy 一个复制操作的类
前言js有一个31k多的star的开源复制库:clipboard.js;但是一些简单复制并不想安装一个库来解决,所以就想自己写一个。copy所需要的东西Selection 对象用于获取被用户选中的部分,通过toString()方法可以获取被选中的文本内容,以及js操作选中。MDN文档:SelectionexecCommand 对象用于以命令的形式来操作网页的内容,说白了就是用它来实现复制文本操作,复制的是选中的文本MDN文档:execCommand 需要注意的是,execCommand在未来将会被遗弃,因为这个api本身是从ie浏览器那边继承的,久而久之各大浏览器都对其做了兼容,虽然...
对象扁平化
前言后端返回给前端的数据,有时候会是一个多层级对象,但是我们前端使用的时候,for循环遍历渲染时,多层级对象往往需要进行单独处理,因为还需要判断这个key值是否存在,否则会报错。强行让后端改变数据结构又好像不现实,无奈,只有自己处理了。掘金看到一位大佬文章《【算法】JS 实现对象的扁平化》感觉很合适,逻辑清晰。要求将对象中的层级扁平化,改成如下格式:// 实现一个 flatten 函数,实现如下的转换功能 const obj = { a: 1, b: [1, 2, { c: true }], c: { e: 2, f: 3 }, g: null, }; // 转换为 l...
javascript 生成随机密码,指定位数,难度(大小写、数字、特殊字符)
原理也没啥好藏着掖着的,就是为了保证密码难度,开头的字符一定是满足安全需要的,比如要求大小写数字加特殊字符,那么开头四位就一定是:大写一位、小写一位、数字一位、特殊字符一位;然后剩下的随机。/** * @description: 随机密码 * @param {*} len 密码位数 * @param {*} mode 密码难度:hide(大小写数字特殊字符)、medium(大小写数字)、low(小写数字) * @Date: 2021-07-02 15:52:32 * @Author: mulingyuer */ export const randomPass = functi...
base64转file文件方法
使用canvas操作内容后,如果想保存图片之类的操作,就无可避免的要处理这一步,因为canvas导出的是base64格式的文件,如果你只做预览还好,存储的话,就要想办法了。我的想法是转成上传文件的那种file格式。方法如下:/** * @description: 将base64转换为文件对象 * @param {*} dataUrl base64 * @param {*} fileName 文件名 * @Date: 2021-06-30 14:33:47 * @Author: mulingyuer */ export function dataURLtoFile(dataUr...