Creates shallow and deep clones of JavaScript values supporting arrays, objects, primitives, dates, maps, sets, and more.
npx @tessl/cli install tessl/npm-lodash-clone@4.5.0Lodash Clone provides comprehensive cloning functionality for JavaScript values, supporting both shallow and deep cloning operations with customization options. Part of the Lodash utility library, these functions handle a wide range of JavaScript types including arrays, objects, primitives, dates, maps, sets, regular expressions, and more.
npm install lodashimport { clone, cloneDeep, cloneWith, cloneDeepWith } from "lodash";For CommonJS:
const { clone, cloneDeep, cloneWith, cloneDeepWith } = require("lodash");Full lodash import:
import _ from "lodash";
// Use as _.clone(), _.cloneDeep(), etc.import { clone, cloneDeep } from "lodash";
// Shallow clone - shared references for nested objects
const original = { a: 1, b: { c: 2 } };
const shallow = clone(original);
console.log(shallow.b === original.b); // => true
// Deep clone - completely independent copy
const deep = cloneDeep(original);
console.log(deep.b === original.b); // => false
// Works with arrays
const arr = [{ name: "Alice" }, { name: "Bob" }];
const clonedArr = clone(arr);
console.log(clonedArr[0] === arr[0]); // => true (shallow)
const deepArr = cloneDeep(arr);
console.log(deepArr[0] === arr[0]); // => false (deep)Lodash clone functionality is built around several key architectural components:
baseClone function serves as the central implementation handling all clone operations with parameters for depth, customization, and circular reference trackingtoStringTaglastIndex on RegExp objects, index and input on RegExp exec results, and constructor relationshipsCreates a shallow clone of a value where nested objects and arrays are shared between the original and clone.
/**
* Creates a shallow clone of `value`.
* @param {*} value The value to clone.
* @returns {*} Returns the cloned value.
*/
function clone(value);Supported Types:
lastIndex preservedUnsupported Types: Returns empty object {} for functions, DOM nodes, WeakMaps, error objects, generators
Usage Examples:
// Basic shallow cloning
const obj = { a: 1, b: { c: 2 } };
const cloned = clone(obj);
cloned.a = 10;
cloned.b.c = 20;
console.log(obj.a); // => 1 (independent)
console.log(obj.b.c); // => 20 (shared reference)
// Array cloning
const numbers = [1, 2, 3];
const clonedNumbers = clone(numbers);
console.log(clonedNumbers); // => [1, 2, 3]
// Date cloning
const date = new Date();
const clonedDate = clone(date);
console.log(clonedDate instanceof Date); // => trueLike clone but accepts a customizer function to produce the cloned value.
/**
* This method is like `clone` except that it accepts `customizer` which
* is invoked to produce the cloned value.
* @param {*} value The value to clone.
* @param {Function} [customizer] The function to customize cloning.
* @returns {*} Returns the cloned value.
*/
function cloneWith(value, customizer);Customizer Function:
(value [, index|key, object, stack])undefined to handle cloning normallyUsage Examples:
// Custom DOM node cloning
function customizer(value) {
if (value && value.nodeType === 1) { // Element node
return value.cloneNode(false);
}
}
const el = cloneWith(document.body, customizer);
console.log(el === document.body); // => false
console.log(el.nodeName); // => 'BODY'
// Custom handling for specific types
function typeCustomizer(value) {
if (typeof value === 'symbol') {
return Symbol(value.description);
}
}
const obj = { sym: Symbol('test') };
const customCloned = cloneWith(obj, typeCustomizer);Creates a deep clone of a value where all nested objects and arrays are recursively cloned.
/**
* This method is like `clone` except that it recursively clones `value`.
* @param {*} value The value to recursively clone.
* @returns {*} Returns the deep cloned value.
*/
function cloneDeep(value);Usage Examples:
// Deep object cloning
const original = {
user: { name: "Alice", profile: { age: 25 } },
tags: ["admin", "user"]
};
const deepCloned = cloneDeep(original);
deepCloned.user.profile.age = 30;
deepCloned.tags.push("moderator");
console.log(original.user.profile.age); // => 25 (unchanged)
console.log(original.tags.length); // => 2 (unchanged)
// Circular reference handling
const circular = { a: 1 };
circular.self = circular;
const clonedCircular = cloneDeep(circular);
console.log(clonedCircular.self === clonedCircular); // => true
// Complex nested structures with multiple circular references
const complex = { data: { items: [] } };
complex.data.parent = complex;
complex.data.items.push({ ref: complex.data });
const clonedComplex = cloneDeep(complex);
console.log(clonedComplex.data.parent === clonedComplex); // => true
console.log(clonedComplex.data.items[0].ref === clonedComplex.data); // => trueLike cloneWith but recursively clones the value with customization.
/**
* This method is like `cloneWith` except that it recursively clones `value`.
* @param {*} value The value to recursively clone.
* @param {Function} [customizer] The function to customize cloning.
* @returns {*} Returns the deep cloned value.
*/
function cloneDeepWith(value, customizer);Usage Examples:
// Custom deep cloning for DOM elements
function domCustomizer(value) {
if (value && value.nodeType === 1) {
return value.cloneNode(true); // Deep clone DOM
}
}
const container = cloneDeepWith(document.getElementById('container'), domCustomizer);
// Custom handling for class instances
function classCustomizer(value) {
if (value instanceof MyClass) {
return new MyClass(value.getData());
}
}
const complex = {
instance: new MyClass(),
nested: { another: new MyClass() }
};
const customDeepCloned = cloneDeepWith(complex, classCustomizer);/**
* Customizer function for clone operations
* @callback Customizer
* @param {*} value - The value being cloned
* @param {number|string} [index] - The index or key of value
* @param {Object} [object] - The parent object of value
* @param {Object} [stack] - The stack for tracking circular references
* @returns {*} The custom cloned value or undefined for default handling
*/
/**
* Cloneable value types supported by lodash clone functions
* @typedef {Array|ArrayBuffer|boolean|Date|Map|number|Object|RegExp|Set|string|symbol|TypedArray} CloneableValue
*/Lodash clone functions automatically detect and handle circular references to prevent infinite recursion:
// Self-referencing object
const obj = { name: "parent" };
obj.self = obj;
const cloned = cloneDeep(obj);
console.log(cloned.self === cloned); // => true (maintains circularity)
// Cross-referencing objects
const a = { name: "a" };
const b = { name: "b", ref: a };
a.ref = b;
const clonedA = cloneDeep(a);
console.log(clonedA.ref.ref === clonedA); // => trueClone functions preserve important properties and metadata:
// RegExp lastIndex preservation
const regex = /test/g;
regex.lastIndex = 5;
const clonedRegex = clone(regex);
console.log(clonedRegex.lastIndex); // => 5
// RegExp exec result properties (index and input)
const execResult = /(\w+)/.exec("hello world");
execResult.customProp = "added";
const clonedResult = clone(execResult);
console.log(clonedResult.index); // => 0 (preserved)
console.log(clonedResult.input); // => "hello world" (preserved)
console.log(clonedResult.customProp); // => "added" (preserved)
// Array expando properties
const arr = [1, 2, 3];
arr.customProperty = "custom";
const clonedArr = clone(arr);
console.log(clonedArr.customProperty); // => "custom"In Node.js environments, Buffer objects are properly cloned:
// Node.js Buffer handling
const buffer = Buffer.from("hello", "utf8");
const clonedBuffer = clone(buffer);
console.log(Buffer.isBuffer(clonedBuffer)); // => true
console.log(clonedBuffer.toString()); // => "hello"
console.log(clonedBuffer === buffer); // => false (different instances)Clone functions handle edge cases gracefully:
{}// State management (shallow clone for immutability)
const newState = { ...state, updates: clone(state.updates) };
// API response processing (deep clone for data manipulation)
const processedData = cloneDeep(apiResponse);
processData(processedData); // Safe to mutate
// Configuration merging with custom handling
const config = cloneDeepWith(defaultConfig, (value) => {
if (Array.isArray(value)) {
return [...value]; // Custom array handling
}
});