Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Deep clone in javascript

Tags:

javascript

How do you deep clone a JavaScript object?

I know there are various functions based on frameworks like JSON.parse(JSON.stringify(o)) and $.extend(true, {}, o) but I don't want to use a framework like that.

What is the most elegant or efficient way to create a deep clone.

We do care about edge cases like cloning array's. Not breaking prototype chains, dealing with self reference.

We don't care about supporting copying of DOM objects and like because .cloneNode exists for that reason.

As I mainly want to use deep clones in node.js using ES5 features of the V8 engine is acceptable.

[Edit]

Before anyone suggests let me mention there is a distinct difference between creating a copy by prototypically inheriting from the object and cloning it. The former makes a mess of the prototype chain.

[Further Edit]

After reading your answer I came to the annoying discovery that cloning entire objects is a very dangerous and difficult game. Take for example the following closure based object

var o = (function() {      var magic = 42;       var magicContainer = function() {           this.get = function() { return magic; };           this.set = function(i) { magic = i; };      }        return new magicContainer; }());  var n = clone(o); // how to implement clone to support closures 

Is there any way to write a clone function that clones the object, has the same state at time of cloning but cannot alter the state of o without writing a JS parser in JS.

There should be no real world need for such a function anymore. This is mere academic interest.

like image 702
Raynos Avatar asked Dec 16 '10 10:12

Raynos


People also ask

How do you make a deep copy in JavaScript?

Copy an Object With Object. assign() was the most popular way to deep copy an object. Object. assign() will copy everything into the new object, including any functions. Mutating the copied object also doesn't affect the original object.

What is a deep clone in JavaScript?

A deep copy is a copy of all elements of the original object. Changes made to the original object will not be reflected in the copy. In this article, you will create deep copies of objects using the Lodash library.

Does JavaScript have deep copy?

Like most other programming languages JavaScript allows supports the concept of deep copy and shallow copy. Shallow Copy: When a reference variable is copied into a new reference variable using the assignment operator, a shallow copy of the referenced object is created.


2 Answers

Very simple way, maybe too simple:

var cloned = JSON.parse(JSON.stringify(objectToClone)); 
like image 162
G. Ghez Avatar answered Oct 21 '22 09:10

G. Ghez


It really depends what you would like to clone. Is this a truly JSON object or just any object in JavaScript? If you would like to do any clone, it might get you into some trouble. Which trouble? I will explain it below, but first, a code example which clones object literals, any primitives, arrays and DOM nodes.

function clone(item) {     if (!item) { return item; } // null, undefined values check      var types = [ Number, String, Boolean ],          result;      // normalizing primitives if someone did new String('aaa'), or new Number('444');     types.forEach(function(type) {         if (item instanceof type) {             result = type( item );         }     });      if (typeof result == "undefined") {         if (Object.prototype.toString.call( item ) === "[object Array]") {             result = [];             item.forEach(function(child, index, array) {                  result[index] = clone( child );             });         } else if (typeof item == "object") {             // testing that this is DOM             if (item.nodeType && typeof item.cloneNode == "function") {                 result = item.cloneNode( true );                 } else if (!item.prototype) { // check that this is a literal                 if (item instanceof Date) {                     result = new Date(item);                 } else {                     // it is an object literal                     result = {};                     for (var i in item) {                         result[i] = clone( item[i] );                     }                 }             } else {                 // depending what you would like here,                 // just keep the reference, or create new object                 if (false && item.constructor) {                     // would not advice to do that, reason? Read below                     result = new item.constructor();                 } else {                     result = item;                 }             }         } else {             result = item;         }     }      return result; }  var copy = clone({     one : {         'one-one' : new String("hello"),         'one-two' : [             "one", "two", true, "four"         ]     },     two : document.createElement("div"),     three : [         {             name : "three-one",             number : new Number("100"),             obj : new function() {                 this.name = "Object test";             }            }     ] }) 

And now, let's talk about problems you might get when start cloning REAL objects. I'm talking now, about objects which you create by doing something like

var User = function(){} var newuser = new User(); 

Of course you can clone them, it's not a problem, every object expose constructor property, and you can use it to clone objects, but it will not always work. You also can do simple for in on this objects, but it goes to the same direction - trouble. I have also included clone functionality inside the code, but it's excluded by if( false ) statement.

So, why cloning can be a pain? Well, first of all, every object/instance might have some state. You never can be sure that your objects doesn't have for example an private variables, and if this is the case, by cloning object, you just break the state.

Imagine there is no state, that's fine. Then we still have another problem. Cloning via "constructor" method will give us another obstacle. It's an arguments dependency. You never can be sure, that someone who created this object, did not did, some kind of

new User({    bike : someBikeInstance }); 

If this is the case, you are out of luck, someBikeInstance was probably created in some context and that context is unkown for clone method.

So what to do? You still can do for in solution, and treat such objects like normal object literals, but maybe it's an idea not to clone such objects at all, and just pass the reference of this object?

Another solution is - you could set a convention that all objects which must be cloned should implement this part by themselves and provide appropriate API method ( like cloneObject ). Something what cloneNode is doing for DOM.

You decide.

like image 30
nemisj Avatar answered Oct 21 '22 08:10

nemisj