js 双对象对比拷贝数据
应用场景:
1、两个深层次对象
2、第一个对象为模板对象,第二个对象为返回的实际数据对象(简称实例对象)
3、如果一个属性在实例对象内,就拿取实例对象的这个属性;如果没有,就从模板对象里面拿取。如果某个属性是数组对象,那么实例对象的这个属性内每一个数组对象都要与模板对象的模板数组对象比较
1 // 引用lodash插件的深拷贝方法
2 import { cloneDeep } from "lodash";
3
4 // 从原型上判断这个对象的类型是什么
5 const checkType = (Obj) => {
6 return Object.prototype.toString.call(Obj).slice(8, -1);
7 };
8
9 // objA 模板对象; objB 已实例对象
10 const mergeObjects = (objA = {}, objB = {}) => {
11
12 // 如果模板是空对象,那就直接返回空对象
13 if (!Object.keys(objA)) {
14 return {};
15 }
16
17 // 深拷贝,防止指针错误
18 const cloneObjA = cloneDeep(objA);
19
20 // 新建返回的对象以已实例对象为基础
21 const returnObj = ![null].includes(objB) ? cloneDeep(objB) : {};
22 // 循环模板对象开始赋值
23 for (let key in cloneObjA) {
24 // 判断 当前(键/key)是否为对象的自有属性:只有自有属性才进行赋值操作
25 if (cloneObjA.hasOwnProperty(key)) {
26 // 判断当前数据类型:
27 switch (checkType(cloneObjA[key])) {
28 // 如果是数组,则拿取 模板对象 的数组对象模板 进行下一层次的比较赋值
29 case "Array":
30 // 如果返回对象已经有了这个属性且是数组,将数组的每一项都基于模板的数组对象,进行比较赋值,然后map出一个新对象
31 if (checkType(returnObj[key]) === "Array") {
32 returnObj[key] = returnObj[key].map((obj) => mergeObjects(objA[key][0], obj) );
33 } else {
34 // 如果返回对象还没有这个属性,则将模板的数组对象尽心比较一个空对象进行复制,并把这个新返回的对象放进数组
35 if(cloneObjA[key].length == 0){ // cloneObjA[key]是一个空数组,直接赋值
36 returnObj[key] = cloneObjA[key]
37 }else{ // cloneObjA[key]不是一个空数组,说明cloneObjA[key]内必然有一个模板,将这个模板赋值给实例对象
38 returnObj[key] = [mergeObjects(cloneObjA[key][0], {})];
39 }
40 }
41 break;
42
43 case "Object": // 如果是对象,无论返回对象有没有这个属性,都要进行比较赋值
44 returnObj[key] = mergeObjects(cloneObjA[key], returnObj[key]);
45 break;
46
47 case "Date": // 如果是date,返回对象将实例一个时间
48 returnObj[key] = key in returnObj ? new Date(returnObj[key].valueOf()) : new Date(cloneObjA[key].valueOf()) ;
49 break;
50
51 case "RegExp": // 如果是RegExp
52 returnObj[key] = key in returnObj ? new RegExp(returnObj[key]) : new RegExp(cloneObjA[key]);
53 break;
54
55 default: // 默认情况先,字符串、数字
56 returnObj[key] = key in returnObj ? returnObj[key] : cloneObjA[key];
57 break;
58 }
59 }
60 }
61 return returnObj;
62 };
63 export default mergeObjects;
忍一时,越想越气;
退一步,哎呦我去!