DEV Community

What's the best way to deeply clone an object in JavaScript?

Jasterix on August 01, 2020

I recently attempted a code challenge where I needed to deeply clone an object. Prior to this I learned to do this by converting it to JSON. But ac...
Collapse
 
masterroshan profile image
TJ Johnson

A library is just a collection of solutions written in a way that they can be reusable. Here is the module in lodash that contains the logic for the deep clone github.com/lodash/lodash/blob/mast..., it's imported from this module github.com/lodash/lodash/blob/mast..., which is the module you would use in your code.

Collapse
 
patarapolw profile image
Pacharapol Withayasakpunt • Edited

There seems to be no native way, but it is as simple as,

function deepClone(o) {
  /**
   * This excludes null
   */
  if (o && typeof o === 'object') {
    if (Array.isArray(o)) {
      return o.map((a) => deepClone(a))
    } else if (o.constructor === Object) {
      return Object.entries(o).reduce((prev, [k, v]) => ({ ...prev, [k]: deepClone(v) }), {})
    }

    /**
     * Now it depends on how you would recreate the Object, or not...
     */
    return o
  }

  /**
   * BTW, function is another important case you might consider...
   */
  return o
}

A perfect way is simply,

/**
 * Yes, that dangerousLoad
 * js-yaml's dump also supports several options
 */
yaml.load(yaml.dump(o))
Collapse
 
jasterix profile image
Jasterix

This is helpful. Thanks!!

Collapse
 
pengeszikra profile image
Peter Vivo • Edited

Are you means?

const base = {
  a: {
   b: [1,2,4],
   c: 'call me c'
  }, 
  d: p => p * 2, 
  get orig(){ return base}
};

const result = deepCopy(base);

test cases (mandatory true)

  result.a !== test.a
  result.a.b !== test.a.b
  result.a.c === test.a.c
  result.d !== test.d
  result.d(42) === test.d(42)
  test.orig === test
  result.orig === test
  result.orig !== result
Collapse
 
jasterix profile image
Jasterix

This is awesome! Thanks for also adding the test cases

Collapse
 
jalal246 profile image
Jalal 🚀
const deeplyCloned = object.assign({}, myObj)
Collapse
 
penguinsource profile image
Mihai

If it's not a nested object, it's really nice to use the spread operator
const newObject = { ..currentObject };

If it's a nested or deeply nested object, it's much safer to use
const newObject = JSON.parse(JSON.stringify(currentObject))

in a nutshell:
const cloneDeep = (obj) => {
return JSON.parse(JSON.stringify(obj))
}

I should say i haven't taken the time to see any performance detriments, if any, appear.

Collapse
 
jalal246 profile image
Jalal 🚀

cloning nested object is like diving into a black hole

Collapse
 
kevindsteeleii profile image
Kevin Steele

let obj = {stuff: {
more_stuff: "this",
list: [1,2,3]},
}

JSON.parse(JSON.stringify(obj))

Collapse
 
jasterix profile image
Jasterix

This is only a shallow clone so nested reference types would not be cloned

Collapse
 
kevindsteeleii profile image
Kevin Steele