CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-lodash-clone

Creates shallow and deep clones of JavaScript values supporting arrays, objects, primitives, dates, maps, sets, and more.

Overview
Eval results
Files

Lodash Clone

Lodash 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.

Package Information

  • Package Name: lodash
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install lodash

Core Imports

import { 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.

Basic Usage

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)

Architecture

Lodash clone functionality is built around several key architectural components:

  • Core Engine: The baseClone function serves as the central implementation handling all clone operations with parameters for depth, customization, and circular reference tracking
  • Type Routing: Specialized clone handlers route different JavaScript types to optimized cloning strategies based on their toStringTag
  • Circular Reference Protection: A stack-based tracking system prevents infinite recursion when cloning objects with circular references
  • Property Preservation: Special logic preserves important properties like lastIndex on RegExp objects, index and input on RegExp exec results, and constructor relationships
  • Customization Layer: Optional customizer functions allow override of default cloning behavior at any level of the object tree
  • Type-Specific Handlers: Dedicated functions for complex types like ArrayBuffers, typed arrays, Maps, Sets, and Node.js Buffers ensure correct cloning semantics

Capabilities

Shallow Clone

Creates 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:

  • Arrays: Standard arrays and array-like objects
  • ArrayBuffers: Binary data buffers with proper byte copying
  • Booleans: Boolean primitives and Boolean objects
  • Dates: Date objects with preserved time values
  • Maps: Map objects with all key-value pairs preserved
  • Numbers: Number primitives and Number objects
  • Objects: Plain objects and object instances
  • RegExp: Regular expressions with source, flags, and lastIndex preserved
  • Sets: Set objects with all values preserved
  • Strings: String primitives and String objects
  • Symbols: Both symbol primitives and Symbol objects
  • Typed Arrays: All typed array types (Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array)
  • Arguments Objects: Cloned as plain objects with length property
  • Buffers: Node.js Buffer objects (when available)

Unsupported 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); // => true

Shallow Clone with Customizer

Like 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:

  • Called with arguments: (value [, index|key, object, stack])
  • Return undefined to handle cloning normally
  • Return any other value to use as the cloned result

Usage 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);

Deep Clone

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); // => true

Deep Clone with Customizer

Like 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);

Type Definitions

/**
 * 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
 */

Advanced Features

Circular Reference Handling

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); // => true

Property Preservation

Clone 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"

Buffer Cloning (Node.js)

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)

Error Handling

Clone functions handle edge cases gracefully:

  • Uncloneable values (functions, DOM nodes, WeakMaps, error objects): Return empty objects {}
  • Null/undefined: Return as-is
  • Primitives: Return as-is (numbers, strings, booleans)
  • Circular references: Detected and handled properly in deep clone operations
  • Invalid customizer: Ignored if not a function, falls back to default behavior

Performance Notes

  • Shallow cloning is faster and uses less memory
  • Deep cloning is more expensive but provides complete independence
  • Customizers add overhead but provide flexibility
  • Consider using shallow clone when nested object sharing is acceptable
  • Use deep clone when complete isolation is required

Common Patterns

// 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
  }
});

Install with Tessl CLI

npx tessl i tessl/npm-lodash-clone
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/lodash.clone@4.5.x