json包含性对比(类型与key的对比,未对值进行对比)

716 阅读2分钟
const dataType = (data) => {
    const type = Object.prototype.toString.call(data);
    const startIndex = type.indexOf(' ') + 1;
    return type.slice(startIndex, -1);
};
const jsonContrast = (obj1, obj2) => {
    let flag = true;
    function compare(obj1, obj2) {
        // 数组情况
        const oldType = dataType(obj1);
        const newType = dataType(obj2);
        if (oldType !== newType) {
            flag = false;
        } else if (oldType === 'Object') { // 对象类型判断属性是否存在
            flag = objectCompare(obj1, obj2);
        } else if (oldType === 'Array') {
            flag = arrayCompare(obj1, obj2);
        }
        if (flag === false) {
            return false;
        } else {
            return true;
        }
    }
    return compare(obj1, obj2);
};
// 对象对比
function objectCompare(obj1, obj2) {
    let flag = true;
    for (let [k, v] of Object.entries(obj1)) { // 方法返回一个给定对象自身可枚举属性的键值对数组
        if (!flag) break; // 如果flag变为false说明数据存在差异应跳出循环
        if (obj2.hasOwnProperty(k)) { // 属性存在,判断类型
            if (dataType(v) === dataType(obj2[k]) && (dataType(v) === 'Object' || dataType(v) === 'Array')) { // 对象类型
                flag = jsonContrast(v, obj2[k]);
            } else if (dataType(v) !== dataType(obj2[k])) { // 其他类型
                flag = false;
            }
        } else {
            flag = false;
        }
    }
    if (flag === false) {
        return false;
    } else {
        return true;
    }
}
// 数组对比
function arrayCompare(obj1, obj2) {
    let flag = true;
    let arrFlag = true;
    let objFlag = true;
    const obj1_statistics = {
        String: 0,
        Number: 0,
        Boolean: 0,
        Array: 0,
        Object: 0
    };
    const obj2_statistics = {
        String: 0,
        Number: 0,
        Boolean: 0,
        Array: 0,
        Object: 0
    };
    const tag = ['String', 'Number', 'Boolean', 'Array', 'Object'];
    const obj1_data_arr = [];
    const obj2_data_arr = [];
    let obj1_data_obj = [];
    const obj2_data_obj = [];

    // 数组对比首先对比长度
    if (obj1.length > obj2.length) {
        flag = false;
    } else {
        // 因为数组中存在多个相同类型,且顺序可以是不固定的,需要对拉个数据的统一数据类型分别进行统计
        // 且如果是复杂类型的数据还需做,另外存储做对比,也许新数据的复杂类型会比老数据多,也有可能存在两个对象的内容相同的情况,以及数据的所在的前后顺序不一致等情况需要做单独处理
        for (let i in obj1) {
            const type = dataType(obj1[i]);
            ++obj1_statistics[type];
            if (type === 'Array') {
                obj1_data_arr.push(obj1[i]);
            }
            if (type === 'Object') {
                obj1_data_obj.push(obj1[i]);
            }
        }
        for (let i in obj2) {
            const type = dataType(obj2[i]);
            ++obj2_statistics[type];
            if (type === 'Array') {
                obj2_data_arr.push(obj2[i]);
            }
            if (type === 'Object') {
                obj2_data_obj.push(obj2[i]);
            }
        }
        // 数据处理完成之后,首先比较数据统计数量,如果新数据两小于老数据量说明数据有差异
        const statistics_result = tag.findIndex(t => obj1_statistics[t] > obj2_statistics[t]);
        if (statistics_result === -1) {
obj1_data_obj = obj1_data_obj.sort((a, b) => Object.keys(b).length - Object.keys(a).length); // 对旧数据对象进行排序,key值越多越靠前优先比较
            arrFlag = children(obj1_data_arr, obj2_data_arr);
            objFlag = children(obj1_data_obj, obj2_data_obj);
        } else {
            flag = false;
        }
    }

    if (!arrFlag || !objFlag) {
        flag = false;
    }
    if (flag === false) {
        return false;
    } else {
        return true;
    }
}

function children(obj1_data, obj2_data) {
    let flag = true;
    let chelidFlag = true;
    outside: for (let i = 0; i < obj1_data.length; i++) { // 为for循环添加label便于在内部终止循环
        for (let j = 0; j < obj2_data.length; j++) {
            if (dataType(obj1_data[i]) === dataType(obj2_data[j]) && (dataType(obj1_data[i]) === 'Array' || dataType(obj1_data[i]) === 'Object')) {
                flag = jsonContrast(obj1_data[i], obj2_data[j]);
                if (flag === true) {
                    if (obj1_data.length !== i) {
                        obj1_data.splice(i, 1);
                        obj2_data.splice(j, 1);
                        chelidFlag = children(obj1_data, obj2_data);
                        if (chelidFlag === false) {
                            break outside;
                        }
                    }
                    break outside;
                }
            }
        }
    }

    if (flag === false || chelidFlag === false) {
        return false;
    } else {
        return true;
    }
}
//设定json--准备调用
var jsonA = {
    "a": { b: 2 },
    "d": [1, [[], { a: 1, b: [{ d: [{ e: [{}, []] }] }] }, { a: 1, b: 2 }, { a: [{ b: 1 }] }, 1]]
};
var jsonB = {
    "a": { b: 2 },
    "d": [1, [{ a: [{ b: 1 }] }, [], { a: 1, b: [{ d: [{ e: [[], {}] }] }] }, { d: 1 }, { a: 1, b: 1 }, 1]]
};
console.log(jsonContrast(jsonA, jsonB), '???');