limu
Version:
A fast js lib of immutable data, based on shallow copy on read and mark modified on write mechanism
109 lines (98 loc) • 2.45 kB
text/typescript
/*---------------------------------------------------------------------------------------------
* Licensed under the MIT License.
*
* @Author: fantasticsoul
*--------------------------------------------------------------------------------------------*/
import type { ObjectLike } from '../inner-types';
import { isMap, isObject, isPrimitive, isSet } from '../support/util';
export function deepCopy<T = ObjectLike>(obj: T): T {
const innerDeep = (obj: any) => {
if (isPrimitive(obj)) {
return obj;
}
// TODO: 或许这里通过 metaVer 能够解决多引用问题 ( see 3.4.2 )
// TODO: 传入参数 reuse,确定是否走逻辑查看 meta.modified,并复用 meta.copy or meta.self
let newNode = obj;
if (Array.isArray(obj)) {
newNode = obj.slice();
newNode.forEach((item: any, idx: number) => {
newNode[idx] = innerDeep(item);
});
}
if (isSet(obj)) {
const tmpArr = Array.from(obj);
tmpArr.forEach((item, idx) => {
tmpArr[idx] = innerDeep(item);
});
newNode = new Set(tmpArr);
}
if (isMap(obj)) {
newNode = new Map(obj) as Map<string, any>;
(newNode as Map<string, any>).forEach((value, key) => {
newNode.set(key, innerDeep(value));
});
}
if (isObject(obj)) {
newNode = {};
Object.keys(obj).forEach((key) => {
newNode[key] = innerDeep(obj[key]);
});
}
return newNode;
};
return innerDeep(obj);
}
export function makeCopy(val: any) {
if (Array.isArray(val)) {
return val.slice();
}
if (isObject(val)) {
return { ...val };
}
if (isMap(val)) {
return new Map(val);
}
if (isSet(val)) {
return new Set(val);
}
return val;
}
/**
* 尝试生成copy
* @param val
* @returns
*/
export function tryMakeCopy(val: any, readOnly?: boolean) {
if (readOnly) {
return val;
}
if (Array.isArray(val)) {
return val.slice();
}
let copy = val;
if (val && isObject(val)) {
copy = { ...val };
}
if (isMap(val)) {
copy = new Map(val);
}
if (isSet(val)) {
copy = new Set(val);
}
return copy;
}
// 调用处已保证 meta 不为空
export function mayMakeCopy(
ori: any,
options: {
immutBase: boolean;
readOnly: boolean;
},
) {
// LABEL: SEE IF IMMUT HAS MEM LEAK
if (options.immutBase) {
return ori;
}
const copy = tryMakeCopy(ori, options.readOnly);
return copy;
}