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.
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.
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.
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.
Very simple way, maybe too simple:
var cloned = JSON.parse(JSON.stringify(objectToClone));
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With