@mt-kit/utils
Version:
88 lines • 2.86 kB
JavaScript
/* eslint-disable guard-for-in */
/* eslint-disable @typescript-eslint/no-empty-object-type */
import isFunction from "../is-function";
import isObject from "../is-object";
/**
* 深拷贝
*
* @param value
* @param map 外部使用的时候,不需要传入
* @return value
*
* 对所有类型都进行了拷贝
*
* lodashjs、underscorejs 对函数、Symbol、Set、Map 等没做深拷贝处理
*
* 不建议使用:JSON.parse(JSON.stringify(value)); 它存在以下缺陷(案例见 ../stories/demo-clone-deep.html):
* ① 无法解析 Symbol 作为 key 或者 value
* ② 无法循环引用
*/
export default function cloneDeep(value, map = new WeakMap()) {
try {
// Set 类型
if (value instanceof Set) {
if (map.has(value)) {
return map.get(value);
}
const newSet = new Set();
map.set(value, newSet);
value.forEach(item => {
newSet.add(cloneDeep(item, map));
});
return newSet;
}
// Map 类型
if (value instanceof Map) {
if (map.has(value)) {
return map.get(value);
}
const newMap = new Map();
map.set(value, newMap);
value.forEach((val, key) => {
newMap.set(cloneDeep(key, map), cloneDeep(val, map));
});
return newMap;
}
// Symbol 类型
if (typeof value === "symbol") {
return Symbol(value.description);
}
// 函数类型
if (isFunction(value)) {
return function (...args) {
return value.apply(this, args);
};
}
// 对象类型
if (!isObject(value)) {
return value;
}
// 判断 map 中是否有值,有了直接 return
if (map.has(value)) {
return map.get(value);
}
// 判断传入的对象是数组, 还是对象
const newValue = Array.isArray(value) ? [] : {};
// Map 没有值
map.set(value, newValue);
for (const key in value) {
newValue[key] = cloneDeep(value[key], map);
}
// Symbol 作为 key 的处理(这个可以不做 Symbol(sKey.description) 处理)
const symbolKeys = Object.getOwnPropertySymbols(value);
for (const sKey of symbolKeys) {
const newSKey = Symbol(sKey.description);
Object.defineProperty(newValue, newSKey, {
enumerable: true,
configurable: true,
writable: true,
value: cloneDeep(Reflect.get(value, sKey), map)
});
}
return newValue;
}
catch {
throw new Error("Deep clone handle error!");
}
}
//# sourceMappingURL=index.js.map