194

Googling for "javascript clone object" brings some really weird results, some of them are hopelessly outdated and some are just too complex, isn't it as easy as just:

let clone = {...original};

Is there anything wrong with this?

hippietrail
  • 15,848
  • 18
  • 99
  • 158
Dmitry Fadeev
  • 2,073
  • 2
  • 12
  • 12
  • 3
    this isn't legal ES6. But if it weren, this isn't a clone: both your clone and original properties point to the same things now. For instance, `original = { a: [1,2,3] }` gives you a clone with `clone.a` literally being `original.a`. Modification through either `clone` or `original` modifies *the same thing*, so no, this is bad =) – Mike 'Pomax' Kamermans Sep 28 '16 at 00:58
  • 2
    @AlbertoRivera It's *kinda* valid JavaScript, in that it's a [stage 2](https://github.com/sebmarkbage/ecmascript-rest-spread) proposal that's likely to be a future addition to the JavaScript standard. – Frxstrem Sep 28 '16 at 01:00
  • @Frxstrem with the question being about ES6, this is not valid JavaScript =) – Mike 'Pomax' Kamermans Sep 28 '16 at 01:01
  • 3
    Shallow or deep cloning? – Felix Kling Sep 28 '16 at 01:05
  • 4
    You're right, it's not valid ES6, it's **valid ES9**. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax – mikemaccana Jul 31 '18 at 15:20
  • @mikemaccana how do you figure? I see it as ecmascript 2015 (6th edition in your link) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#Specifications – Catfish Mar 21 '19 at 00:37
  • From the link "For object literals (new in ECMAScript 2018): `let objClone = { ...obj };`" – mikemaccana Mar 22 '19 at 13:33

11 Answers11

304

This is good for shallow cloning. The object spread is a standard part of ECMAScript 2018.

For deep cloning you'll need a different solution.

const clone = {...original} to shallow clone

const newobj = {...original, prop: newOne} to immutably add another prop to the original and store as a new object.

Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
Mark Shust at M.academy
  • 6,300
  • 4
  • 32
  • 50
  • 20
    However, isn't this just a shallow clone? As in, properties are not cloned recursively, are they? Therefore, original.innerObject === clone.innerObject and changing original.innerObject.property will change clone.innerObject.property. – milanio Apr 03 '18 at 14:46
  • 24
    yes, this is a shallow clone. if you want a deep clone you must use `JSON.parse(JSON.stringify(input))` – Mark Shust at M.academy Apr 04 '18 at 15:30
  • 9
    /!\ JSON.parse(JSON.stringify(input)) messes up dates, undefined, ... It is not the silver bullet for cloning! See: https://www.maxpou.fr/immutability-js-without-library/ – Guillaume Jun 12 '18 at 08:20
  • 3
    So is the hack JSON.stringify()/JSON.parse() really the recommended way to deep clone an object in ES6? I keep seeing it recommended. Disturbing. – png Jun 28 '18 at 18:27
  • 2
    The result is a simple object, not the instance of the original object class (that is true for JSON.stringify/parse, Object.assign and {...originalObj}). The best way to have REAL clone of the object I would suggest to implement clone() method which would make sure correct instance is returned as mentioned by marcel https://stackoverflow.com/a/46785117/343039 – Petr Urban Jul 06 '18 at 12:35
  • 4
    @MarkShust `JSON.parse(JSON.stringify(input))` will not work, because if there `functions` or `infinity` as values it will simply assign `null` in their place. It will only work if the values are simple are `literals` and not `functions`. – backslashN May 23 '19 at 14:19
76

EDIT: When this answer was posted, {...obj} syntax was not available in most browsers. Nowadays, you should be fine using it (unless you need to support IE 11).

Use Object.assign.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }

However, this won't make a deep clone. There is no native way of deep cloning as of yet.

EDIT: As @Mike 'Pomax' Kamermans mentioned in the comments, you can deep clone simple objects (ie. no prototypes, functions or circular references) using JSON.parse(JSON.stringify(input))

Alberto Rivera
  • 3,652
  • 3
  • 19
  • 33
  • 22
    There is one, provided your object is a true object literal, and purely data, in which case `JSON.parse(JSON.stringify(input))` is a proper deep clone. However, the moment prototypes, functions or circular references are in play, that solution no longer works. – Mike 'Pomax' Kamermans Sep 28 '16 at 01:00
  • @Mike'Pomax'Kamermans That's true. Losing functionality for getters and setters is terrible, though... – Alberto Rivera Sep 28 '16 at 01:03
  • If you need a generic function to deep clone any object, check out http://stackoverflow.com/a/13333781/560114. – Matt Browne Sep 28 '16 at 01:10
  • 1
    There is now a way to do [deep cloning natively](https://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-deep-clone-an-object-in-javascript/122704#122704). – Dan Dascalescu Jun 14 '19 at 05:32
  • 1
    @DanDascalescu even though it is experimental, it looks pretty promising. Thanks for the info! – Alberto Rivera Jun 14 '19 at 16:25
8

If the methods you used isn't working well with objects involving data types like Date, try this

Import _

import * as _ from 'lodash';

Deep clone object

myObjCopy = _.cloneDeep(myObj);
shaheer shukur
  • 1,077
  • 2
  • 12
  • 19
  • Just `import _ from 'lodash';` is sufficient. But +1 for "don't reinvent the wheel" answer. – rustyx Sep 19 '19 at 09:36
  • 1
    lodash is bloated. Really no need to pull in lodash just for a simple deep copy. Plenty of other solutions here. This is a really bad answer for web developers looking to build a lean app. – Jason Rice Oct 01 '19 at 15:19
  • Webpack tree-shaking is the solution to that problem Jason. Also you can import just that function: https://www.npmjs.com/package/lodash.clonedeep. +1 for using a known-good solution and not reinventing wheels – jcollum Dec 28 '20 at 23:35
  • lodash clone is not working if u clone instance of your Class which has some private fields/functions... it makes Object where u cannot access these anymore. – To Kra Jul 26 '23 at 14:27
4

You can do it like this as well,

let copiedData = JSON.parse(JSON.stringify(data));
Rafeeque
  • 845
  • 9
  • 13
  • 1
    This will work, but Object's datatype becomes string :( Say for example date object becomes a string with converted values when using stringify – smilyface Jul 09 '21 at 03:54
3

if you don't want to use json.parse(json.stringify(object)) you could create recursively key-value copies:

function copy(item){
  let result = null;
  if(!item) return result;
  if(Array.isArray(item)){
    result = [];
    item.forEach(element=>{
      result.push(copy(element));
    });
  }
  else if(item instanceof Object && !(item instanceof Function)){ 
    result = {};
    for(let key in item){
      if(key){
        result[key] = copy(item[key]);
      }
    }
  }
  return result || item;
}

But the best way is to create a class that can return a clone of it self

class MyClass{
    data = null;
    constructor(values){ this.data = values }
    toString(){ console.log("MyClass: "+this.data.toString(;) }
    remove(id){ this.data = data.filter(d=>d.id!==id) }
    clone(){ return new MyClass(this.data) }
}
marcel
  • 3,231
  • 8
  • 43
  • 76
2

Following on from the answer by @marcel I found some functions were still missing on the cloned object. e.g.

function MyObject() {
  var methodAValue = null,
      methodBValue = null

  Object.defineProperty(this, "methodA", {
    get: function() { return methodAValue; },
    set: function(value) {
      methodAValue = value || {};
    },
    enumerable: true
  });

  Object.defineProperty(this, "methodB", {
    get: function() { return methodAValue; },
    set: function(value) {
      methodAValue = value || {};
    }
  });
}

where on MyObject I could clone methodA but methodB was excluded. This occurred because it is missing

enumerable: true

which meant it did not show up in

for(let key in item)

Instead I switched over to

Object.getOwnPropertyNames(item).forEach((key) => {
    ....
  });

which will include non-enumerable keys.

I also found that the prototype (proto) was not cloned. For that I ended up using

if (obj.__proto__) {
  copy.__proto__ = Object.assign(Object.create(Object.getPrototypeOf(obj)), obj);
}

PS: Frustrating that I could not find a built in function to do this.

Shane Gannon
  • 6,770
  • 7
  • 41
  • 64
1

structured Clone you can Used this method

function Copy_Object(obj) { return structuredClone(obj); }
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/31238071) – Kerel Mar 14 '22 at 10:31
1

UPDATE: 05/31/2023 a new global function was release that allows DEEP COPY called window.structuredClone()

const person1 = {
    address: {
    address1: "my address1", 
    address2: "my address2"
    },
    age: 23
};
console.log(person1)
const person2 = window.structuredClone(person1)
person2.address.address1 = "my new address1"
person2.address.address2= "my new address2"
person2.age = 40
console.log(person1) // person1 was not changed
Bins
  • 65
  • 7
0
We can do that with two way:
1- First create a new object and replicate the structure of the existing one by iterating 
 over its properties and copying them on the primitive level.

let user = {
     name: "John",
     age: 30
    };

    let clone = {}; // the new empty object

    // let's copy all user properties into it
    for (let key in user) {
      clone[key] = user[key];
    }

    // now clone is a fully independant clone
    clone.name = "Pete"; // changed the data in it

    alert( user.name ); // still John in the original object

2- Second we can use the method Object.assign for that 
    let user = { name: "John" };
    let permissions1 = { canView: true };
    let permissions2 = { canEdit: true };

    // copies all properties from permissions1 and permissions2 into user
    Object.assign(user, permissions1, permissions2);

  -Another example

    let user = {
      name: "John",
      age: 30
    };

    let clone = Object.assign({}, user);
It copies all properties of user into the empty object and returns it. Actually, the same as the loop, but shorter.

But Object.assign() not create a deep clone

let user = {
  name: "John",
  sizes: {
    height: 182,
    width: 50
  }
};

let clone = Object.assign({}, user);

alert( user.sizes === clone.sizes ); // true, same object

// user and clone share sizes
user.sizes.width++;       // change a property from one place
alert(clone.sizes.width); // 51, see the result from the other one

To fix that, we should use the cloning loop that examines each value of user[key] and, if it’s an object, then replicate its structure as well. That is called a “deep cloning”.

There’s a standard algorithm for deep cloning that handles the case above and more complex cases, called the Structured cloning algorithm. In order not to reinvent the wheel, we can use a working implementation of it from the JavaScript library lodash the method is called _.cloneDeep(obj).

0

I found a solution which seems to copy functions as well, correct me if this example is an error.

Attention I have not tested this method with more complex object cases, which, for example, would include methods with this for reference

Take for example the price of a breakfast, I have this price available globally but I would like to adjust it individually for a hotel room

// make an object for a booking option
var opt_resa = { breakfast_val: 900 }

// i define a function for opt_resa : 
opt_resa.func = function(){ alert('i am a function'); }

// copy object in modif.opt_resa :
var modif = { opt_resa : {} }

for ( var v in opt_resa ){

    modif.opt_resa[v] = opt_resa[v];
}

// test
modif.opt_resa.breakfast_val = 1500;

// old value
console.log( opt_resa.breakfast_val );
// output : 900

// modified value
console.log( modif.opt_resa.breakfast_val );
// output : 1500

// function copied
modif.opt_resa.func(); 
// this function works
-1

All the methods above do not handle deep cloning of objects where it is nested to n levels. I did not check its performance over others but it is short and simple.

The first example below shows object cloning using Object.assign which clones just till first level.

var person = {
    name:'saksham',
    age:22,
    skills: {
        lang:'javascript',
        experience:5
    }
}

newPerson = Object.assign({},person);
newPerson.skills.lang = 'angular';
console.log(newPerson.skills.lang); //logs Angular

Using the below approach deep clones object

var person = {
    name:'saksham',
    age:22,
    skills: {
        lang:'javascript',
        experience:5
    }
}

anotherNewPerson = JSON.parse(JSON.stringify(person));
anotherNewPerson.skills.lang = 'angular';
console.log(person.skills.lang); //logs javascript
Saksham
  • 9,037
  • 7
  • 45
  • 73
  • JSON.parse/stringify has been mentioned as a poor deep cloning method for [**years**](https://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-deep-clone-an-object-in-javascript/122704#122704). Please check previous answers, as well as related questions. Also, this is not new to ES6. – Dan Dascalescu Jun 14 '19 at 05:34
  • @DanDascalescu I know this and I think it shouldn’t be an issue to use it for simple objects. Others have also mentioned this in their answers in the same post and even as comments. I think it does not deserve a downvote. – Saksham Jun 14 '19 at 18:43
  • Exactly - "other have also mentioned" JSON.parse/stringify in their answers. Why post yet another answer with the same solution? – Dan Dascalescu Jun 15 '19 at 06:43