froebel
Version:
TypeScript utility library
37 lines (30 loc) • 1.29 kB
JavaScript
/**
* Returns a copied version of `value`.
*
* If `value` is primitive, returns `value`.
* Otherwise, properties of `value` are copied recursively. Only `value`'s own
* enumerable properties are cloned. Arrays are cloned by mapping over their
* elements.
*
* If a path in `value` references itself or a parent path, then in the
* resulting object that path will also reference the path it referenced in the
* original object (but now in the resuling object instead of the original).
*/
const clone = globalThis.structuredClone ?? cloneFallback;
export default clone;
function cloneFallback(value) {
const map = new Map();
const replacers = [];
const cloned = _clone(value, map, replacers, undefined);
for (const f of replacers) f();
return cloned;
}
function _clone(v, visited, replacers, replace) {
if (typeof v !== "object" || v === null) return v;
if (visited.has(v)) return replace(v);
visited.set(v, 0);
const cloneNext = (v, r) => _clone(v, visited, replacers, v => replacers.push(() => r(v)));
const cloned = Array.isArray(v) ? v.map((e, i) => cloneNext(e, v => cloned[i] = visited.get(v))) : Object.fromEntries(Object.entries(v).map(([k, e]) => [k, cloneNext(e, v => cloned[k] = visited.get(v))]));
visited.set(v, cloned);
return cloned;
}