Lodash _.clone vs Shallow Clone in JavaScript
This article explains the relationship and technical distinctions
between a general shallow clone in native JavaScript and the
_.clone utility provided by the Lodash library. While
Lodash's _.clone is fundamentally an implementation of a
shallow copy, it differs significantly from native shallow cloning
techniques—such as object spread syntax and
Object.assign—in how it handles specialized data
structures, prototypes, and edge cases.
The Definition of a Shallow Clone
In JavaScript, a shallow clone creates a new compound object and copies the top-level properties from the original source. If a property is a primitive value (like a string, number, or boolean), the value itself is copied. However, if a property is a reference type (like an array or nested object), only the memory reference is copied. As a result, mutations made to nested objects in the clone directly affect the original object.
Native JavaScript provides two common ways to perform a shallow clone:
- The spread operator:
{ ...original }or[ ...original ] Object.assign():Object.assign({}, original)
What Lodash _.clone
Does
The _.clone function in Lodash is explicitly a shallow
clone algorithm, distinct from _.cloneDeep, which
recursively traverses and duplicates nested trees.
Like native techniques, _.clone does not duplicate
nested objects; references to nested structures are shared between the
clone and the source. However, _.clone is an advanced
shallow clone implementation engineered to support diverse JavaScript
types that standard native methods fail to duplicate properly.
Key Differences
1. Handling of Specialized Objects
Native shallow copying techniques are designed for plain objects and arrays. When applied to complex native types, native cloning mechanisms produce broken or empty objects:
- Date Objects: Spreading a
Dateinstance ({ ...new Date() }) returns an empty object{}becauseDateproperties are not enumerable. In contrast,_.clone(new Date())produces a valid, functioningDateinstance with the same timestamp. - RegExp Objects:
{ .../abc/g }produces an empty object._.clone(/abc/g)produces a new, properly configuredRegExpinstance. - Maps and Sets: Native object spread on a
MaporSetloses all stored entries. Lodash_.cloneproduces a newMaporSetcontaining the shallow elements of the original collection. - ArrayBuffers and TypedArrays: Native methods cannot
duplicate buffer allocations. Lodash
_.cloneproperly allocates a new buffer and duplicates the binary data.
2. Prototype Preservation
Native shallow copy methods, such as Object.assign() or
{ ...obj }, always return instances inheriting from
Object.prototype, stripping any custom prototype
chains:
class User {
greet() { return "Hello"; }
}
const user = new User();
const spreadClone = { ...user };
const lodashClone = _.clone(user);
console.log(spreadClone instanceof User); // false (prototype lost)
console.log(lodashClone instanceof User); // true (prototype preserved)_.clone checks the prototype of custom instances and
constructs the new shallow copy using the original prototype, preserving
class methods and inheritance chains.
3. Primitive Safety and Robustness
Native mechanisms can produce runtime exceptions or unexpected
structures when non-object types are provided. Lodash's
_.clone contains built-in type checks: passing a primitive
(e.g., a number or string), null, or undefined
returns the value safely without throwing an error.
Summary
_.clone is not fundamentally different in concept from a
shallow clone; rather, it is a robust, type-aware implementation of one.
While native methods like { ...obj } and
Object.assign are optimized for plain objects, Lodash's
_.clone handles custom classes, Date,
RegExp, Map, Set, and binary
buffers, making it a more dependable choice when copying values of
arbitrary or specialized types.