这几天有用到了merge,总是感觉一直在递归,所以就想能不能不用呢
然后写了一下,依然递归 🤮 但是这么一写还是感觉有些新鲜的
const toString = {}.toString;
const type = (v) => toString.call(v).substring(8).replace(']', '').toLowerCase();
const isSetValue = (v) => ['string', 'number', 'undefined', 'function', 'null'].includes(type(v));
// 直接合并的值,不对比
const valueAssign = (targetObj, sourceObj) => {
if (isSetValue(sourceObj) || isSetValue(targetObj)) {
return sourceObj === undefined ? targetObj : sourceObj;
}
};
const createProxy = (targetObj, sourceObj) => {
const v = valueAssign(targetObj, sourceObj);
if (v) return v;
return new Proxy(targetObj, {
set(target, key, value, receiver) {
const v = valueAssign(target[key], sourceObj[key]);
if (v) {
target[key] = value;
return true;
}
const t = target[key];
const s = sourceObj[key];
const typeT = type(t);
const typeS = type(s);
// 数组和对象类型才去判断合并
switch (true) {
case typeT === 'array' && typeS === 'array':
const tLen = t.length;
const sLen = s.length;
for (let i = 0, n = Math.max(tLen, sLen); i < n; i++) {
target[key][i] = baseDeepMerge(t[i], s[i]);
}
break;
case typeT === 'object' && typeS === 'object':
baseDeepMerge(t, s);
break;
default:
target[key] = s;
break;
}
return true;
},
});
};
const baseDeepMerge = (targetObj, sourceObj) => {
const v = valueAssign(targetObj, sourceObj);
if (v) return v;
const proxyTarget = createProxy(targetObj, sourceObj);
// proxy.a = 3;
Object.assign(proxyTarget, sourceObj);
return targetObj;
};
const deepMerge = (t, ...args) => {
args.forEach((s) => {
baseDeepMerge(t, s);
});
return t;
};
// [
// 1,
// 5,
// {
// b: 5,
// ccc: 1,
// d: 123,
// },
// {
// b: 2,
// },
// ]
console.log(
deepMerge(
[1, { a: 1 }, { b: 2 }], //
[3, 4, { ccc: 1 }, { b: 2 }], //
[1, 5, { b: 5, d: 123 }] //
)
);