封装文件下载:
https://pan.baidu.com/s/13dKvv3nd-Q2r9544O8k46A
提取码:7mg2
兼容性:
Chrome, Firefox, Opera, Safari, Edge, IE 8+
/**
* 对象深度拷贝
*
* @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"
})