clone
Creates a deep copy of an object. Recursively clones all properties of an object, including nested objects and arrays. Handles circular references by maintaining a reference map. Primitive values, functions, and built-in objects like Date and RegExp are handled appropriately.
Installation
npx fragmen add object/cloneSource Code
/**
* Creates a deep copy of an object.
*
* Recursively clones all properties of an object, including nested objects and arrays.
* Handles circular references by maintaining a reference map. Primitive values,
* functions, and built-in objects like Date and RegExp are handled appropriately.
*
* @tags pure, object-manipulation
* @param {T} obj The object to clone
* @returns {T} A deep copy of the input object
*
* @example
* ```typescript
* const original = {
* name: 'John',
* age: 30,
* address: {
* street: '123 Main St',
* city: 'NYC'
* },
* hobbies: ['reading', 'gaming']
* };
*
* const cloned = clone(original);
* cloned.address.city = 'LA';
* console.log(original.address.city); // 'NYC' (unchanged)
* console.log(cloned.address.city); // 'LA'
*
* // Works with arrays
* const arr = [1, { nested: true }, [2, 3]];
* const clonedArr = clone(arr);
* clonedArr[1].nested = false;
* console.log(arr[1].nested); // true (unchanged)
*
* // Handles dates and other built-ins
* const withDate = { created: new Date(), pattern: /test/g };
* const clonedDate = clone(withDate);
* console.log(clonedDate.created instanceof Date); // true
* ```
*/
export function clone<T>(obj: T): T {
return cloneWithMap(obj, new WeakMap());
}
/**
* Internal clone function that maintains a reference map to handle circular references
*/
function cloneWithMap<T>(obj: T, refs: WeakMap<object, unknown>): T {
// Handle primitive values
if (obj === null || typeof obj !== 'object') {
return obj;
}
// Handle circular references
if (refs.has(obj as object)) {
return refs.get(obj as object) as T;
}
// Handle Date objects
if (obj instanceof Date) {
return new Date(obj.getTime()) as T;
}
// Handle RegExp objects
if (obj instanceof RegExp) {
return new RegExp(obj.source, obj.flags) as T;
}
// Handle Arrays
if (Array.isArray(obj)) {
const clonedArray: unknown[] = [];
refs.set(obj as object, clonedArray);
for (let i = 0; i < obj.length; i++) {
clonedArray[i] = cloneWithMap(obj[i], refs);
}
return clonedArray as T;
}
// Handle Objects
const clonedObj = {} as Record<string, unknown>;
refs.set(obj as object, clonedObj);
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
clonedObj[key] = cloneWithMap(
(obj as Record<string, unknown>)[key],
refs
);
}
}
return clonedObj as T;
}
Examples
const original = {
name: 'John',
age: 30,
address: {
street: '123 Main St',
city: 'NYC'
},
hobbies: ['reading', 'gaming']
};
const cloned = clone(original);
cloned.address.city = 'LA';
console.log(original.address.city); // 'NYC' (unchanged)
console.log(cloned.address.city); // 'LA'
// Works with arrays
const arr = [1, { nested: true }, [2, 3]];
const clonedArr = clone(arr);
clonedArr[1].nested = false;
console.log(arr[1].nested); // true (unchanged)
// Handles dates and other built-ins
const withDate = { created: new Date(), pattern: /test/g };
const clonedDate = clone(withDate);
console.log(clonedDate.created instanceof Date); // true
Related Utilities
omit
objectCreates a new object by omitting specified keys from the source object. Returns a new object that contains all properties from the source object except for the specified keys. This is the opposite of the pick utility. The operation is shallow - nested objects are not deeply omitted.
pick
objectCreates a new object composed of the picked object properties. Extracts only the specified keys from the source object, creating a new object with just those properties. Non-existent keys are silently ignored.
has-path
objectChecks if a nested property path exists in an object. Safely traverses nested object properties using a dot-notation path string or an array of keys. Returns true if the path exists (even if the final value is undefined), false if any part of the path is missing.
deep-equal
objectPerforms deep equality comparison between two values
merge
objectChecks if a value is a non-array, non-null object.
chunk
arraySplits an array into chunks of a specified size. Creates a new array containing subarrays (chunks) of the original array, each with a maximum length of the specified size. The last chunk may contain fewer elements if the array length is not evenly divisible by the chunk size.
Quick Actions
Tags
Parameters
objTThe object to clone
Returns
TA deep copy of the input object