js 对象高阶函数 (深拷贝、深合并、深取值、深改值、引用分离)

js 对象高阶函数 (深拷贝、深合并、深取值、深改值、引用分离):


封装文件下载:

https://pan.baidu.com/s/13dKvv3nd-Q2r9544O8k46A
提取码:7mg2

兼容性:

Chrome, Firefox, Opera, Safari, Edge, IE 8+


对象深度拷贝:

  • 支持对象数组间独立拷贝,循环引用对象拷贝,Symbol拷贝
/**
 *  对象深度拷贝
 *
 *  @brief 支持对象数组间独立拷贝,循环引用对象拷贝,Symbol拷贝。
 *  @param {any} source  拷贝源
 *  @param {object} record  拷贝记录(非必须,写入此项可能会影响结果,可用作替换拷贝后的某个值)
 *  @example
    // 引入参数释义
    source = { $1: ... }
    record = [
        {
            // 拷贝源内的某个对象或数组,可选择引用的值
            source: source.$1,

            // 拷贝后的某个值的替换值
            target: $2
        }
    ]
 */
function objClone (source, record) {
     
    var objCloneFN = function (source, record) {
     
        if (typeof source !== "object" || source == null) return source;
        var target = Array.isArray(source) ? [] : {
     }, recordData;
        for (var i = 0; i < (record = record || []).length; i++)
        if (record[i].source === source) recordData = record[i];
        if (recordData) return recordData.target;
        record.push({
      source: source, target: target });
        if (Object.getOwnPropertySymbols) {
     
            var symKeys = Object.getOwnPropertySymbols(source);
            if (symKeys.length > 0) {
     
                symKeys.forEach(function (symKey) {
     
                    if (typeof source[symKey] === "object" && source[symKey] != null) {
     
                        target[symKey] = objCloneFN(source[symKey], record); 
                    } else {
     
                        target[symKey] = source[symKey];
                    }    
                });
            }
        }
        for(var key in source) {
     
            if (Object.prototype.hasOwnProperty.call(source, key)) {
     
                if (typeof source[key] === "object" && source[key] != null) {
     
                    target[key] = objCloneFN(source[key], record);
                } else {
     
                    target[key] = source[key];
                }
            }
        }
        return target;
    };
    return objCloneFN(source, record);
}
// 用法示例:
var a = {
     
        a1: undefined,
        a2: null,
        a3: 123,
        a4: [11, 22, [33, 44], {
     v1: 55, v2: 66}],
        a5: {
     
            v3: 77,
            v4: 88,
            v5: [99, 100],
            v6: {
     
                v7: 111,
                v8: [222, 333]
            }
        },
        a6: ["n1", "n2"],
        a7: {
     
            v9: "n5",
            v10: ["n6", "n7"],
        },
        [Symbol("sym1")]: 98765,
        [Symbol.for("sym2")]: "sym2_val"
    }
    a.loop = a

    var b = objClone(a, [
        {
     
            source: a.a6,
            target: "a.a6 => nnn"
        },
        {
     
            source: a.a7.v10,
            target: (function () {
     
                var source = objClone(a.a7.v10);
                source[1] = "a.a7.v10[1] => nnn";
                return source;
            }())
        }
    ])

    a.a3 = 321
    a.a4[1] = "-22"
    a.a4[2][1] = "-44"
    a.a4[3].v2 = "-66"
    a.a5.v4 = "-88"
    a.a5.v5[1] = "-100"
    a.a5.v6.v7 = "-111"
    a.a5.v6.v8[1] = "-333"

    console.log(a, b)

对象深度合并:

  • 支持对象数组内部合并
/**
 *  对象深度合并
 *
 *  @brief 支持对象数组内部合并。
 *  @param {object} source 合并源
 *  @param {object} target 合并目标(可多个)
 */
function objMerge (source, target) {
     
    for (var extended = {
     }, i = 0; i < arguments.length; i++) {
     
        source = arguments[i];
        for (var key in source) {
     
            if (source.hasOwnProperty(key)) {
     
                if (Object.prototype.toString.call(source[key]) === "[object Object]") {
     
                  extended[key] = arguments.callee(extended[key], source[key]);
                } else {
     
                  extended[key] = source[key];
                }
          }
      }
    }
    return extended;
}
// 用法示例:
var A = {
     
    a: 1,
    b: 2,
    c: 3
}
var B = {
     
    b: 22,
    c: [33, 44],
    d: {
      d1: 55, d2: 56}
}
var C = {
     
    b: 222,
    c: [333],
    d: {
      d2: 556, d3: 557}
}
objMerge(A, B, C)

深度获取对象内部值:

  • 支持扁平化写法获取对象内部值
/**
 *  深度获取对象内部值
 * 
 *  @brief  支持扁平化写法获取对象内部值
 *  @param {String} prop    对象的键名
 *  @param {Object} source  对象的根源 (默认当前作用域)
 */
function objVal (prop, source) {
     
    source = source !== void 0 ? source : this;
    if (typeof source == 'object' && source != null) {
     
        if (prop.indexOf('.') >= 0) {
     
            var keys = prop.split('.');
            for (var i = 0; i < keys.length; i++) {
     
                if (typeof source == 'object' && source != null && source.hasOwnProperty(keys[i])) {
     
                    source = source[keys[i]];
                } else return;
            }
            return source;
        } else if (source.hasOwnProperty(prop)) {
     
            return source[prop];
        }
    }
}
// 用法示例:
var obj = {
     
        aa: {
     
        bb: [{
      cc: [11, 22] }]
    }
}
objVal('aa.bb.0.cc.1', obj)

深度修改对象内部值:

  • 支持扁平化写法修改对象内部值
/**
 *  深度修改对象内部值
 * 
 *  @brief  支持扁平化写法修改对象内部值
 *  @param  {Object}    source  源对象
 *  @param  {Object}    config  修改配置
 *  @param  {Boolean}   isonly  是否只修改存在键的值 ( false: 源对象不存在键时赋新的键和值, 修改的键为非纯数字并且对应源为数组时会将对应数组转化成对象 | true: 源对象不存在键时或修改的键为非纯数字并且对应源为数组时不赋值 )
 *  @return {Object}            修改后的源对象 (引用源对象的地址)
 */
function objValEdit (source, config, isonly) {
     
    if (typeof source == 'object' && source != null && typeof config == 'object' && config != null) {
     
        isonly = isonly === true;
        var unNextArray = function (val, keyName) {
     
            return Object.prototype.toString.call(val) === '[object Array]' && !/^\d+$/.test(keyName);
        };
        var objClone = function (val) {
     
            var res = {
     };
            for (var prop in val) {
     
                if (val.hasOwnProperty(prop)) res[prop] = val[prop];
            }
            return res;
        };
        for (var prop in config) {
     
            var propGroup = prop.split('.');
            if (propGroup.length > 1) {
     
                var keyName = '', objData = source, propbreak = false;
                for (var i = 0; i < propGroup.length - 1; i++) {
     
                    if (typeof objData == 'object' && objData != null) {
     
                        keyName = propGroup[i + 1];
                        if (!isonly) {
     
                            if (typeof objData[propGroup[i]] != 'object' || objData[propGroup[i]] == null) {
     
                                objData[propGroup[i]] = /^\d+$/.test(keyName) ? [] : {
     };
                            }
                            if (unNextArray(objData[propGroup[i]], keyName)) {
     
                                objData[propGroup[i]] = objClone(objData[propGroup[i]]);
                            }
                            objData = objData[propGroup[i]];
                        } else if (objData.hasOwnProperty(propGroup[i])) {
     
                            if (unNextArray(objData[propGroup[i]], keyName)) {
     
                                propbreak = true; break;
                            } else {
     
                                objData = objData[propGroup[i]];
                            }
                        } else {
     
                            propbreak = true; break;
                        }
                    } else {
     
                        propbreak = true; break;
                    }
                }
                if (propbreak) continue;
                if (typeof objData == 'object' && objData != null && (!isonly || objData.hasOwnProperty(keyName))) {
     
                    objData[keyName] = config[prop];
                }
            } else if ((!isonly || source.hasOwnProperty(prop)) && !unNextArray(source, prop)) {
     
                source[prop] = config[prop];
            }
        }
    }
    return source;
}
// 用法示例:
var obj = {
     
    aa: 1,
    bb: 2,
    cc: {
     
        c1: 3,
        c2: 4,
        dd: [5, 6]
    }
}
objValEdit(obj, {
     
    aa: 11,
    zz: 22,
    'bb.b1': 33,
    'cc.c1': 44,
    'cc.c2.0': 55,
    'cc.dd.1': 66,
    'cc.dd.z1.z2': 77
})

对象引用分离器:

  • 多个值合并在一起,不同值之间可通过名称引用
/**
 *  对象引用分离器
 *
 *  @brief 多个值合并在一起,不同值之间可通过名称引用。
 *  @param {object} data  源对象(每个值的 key 为该引用的名称)
 *  @param {array} return---result  分离结果对象
 *  @param {object} return---originData  引用的源对象
 *  @param {object} return---valueList  分离出来的含结果的值列表(以 $1, $2, ... $n 顺序递增)
 *  @param {array} return---stepList  引用键所对应的关系列表
 *  @example
   // 返回参数释义
   {
        valueList: {
            $1: 分离结果值1,
            $2: 分离结果值2,
            ...
        },
        stepList: {
            originName: 源对象内的值名称,
            repeatName: 重复值所对应的源值名称,
            valueName: 结果值对应的名称
        }
    }
 */
function objStep (data) {
     
    var valueList = {
     }, stepList = [], valueRes = [];
    var dataKey = Object.keys(data), stepKey = 0;
    dataKey.forEach(function (dKey) {
     
        var dVal = data[dKey], stepSet = {
      originName: dKey };
        if (typeof dVal == "string" && dataKey.includes(dVal)) {
     
            stepSet.repeatName = data[dKey];
        } else {
     
            stepKey++;
            valueList["$" + stepKey] = dVal;
            stepSet.valueName = "$" + stepKey;
        }
        stepList.push(stepSet);
    });
    stepList.forEach(function (sVal) {
     
        if (sVal.valueName === void 0 && sVal.repeatName) {
     
            var i = 0, j = 0, repeatName = sVal.repeatName;
            while (i < stepList.length && j < stepList.length) {
     
                if (repeatName == stepList[i].originName) {
     
                    if (stepList[i].valueName !== void 0) {
     
                        sVal.valueName = stepList[i].valueName;
                        break;
                    } else {
     
                        if (stepList[i].repeatName) {
     
                            repeatName = stepList[i].repeatName;
                            i = 0, j++;
                        }
                        else break;
                    }
                }
                else i++;
            }
        }
    });
    stepList.forEach(function (sVal) {
     
        valueRes.push(valueList[sVal.valueName]);
    });
    return {
     
        result: valueRes,
        originData: data,
        stepList: stepList,
        valueList: valueList
    };
}
// 用法示例:
objStep({
     
    $1: 111,
    $2: 222,
    $3: "$1",
    $4: 444,
    $5: "$3",
    $6: "$5"
})

你可能感兴趣的:(javascript,javascript,html)