# Deep clone method

I'm quite new to JavaScript and wrote this clone method to be able to clone any kind of object. It works quite well for the cases I've tested until now, but for JSON objects it seemed kind of slow to me. I'm sure there is some additional speed to to squeeze out and a lot of overall improvement to make. But I don't know enough about JavaScript to optimize this.

Object.prototype.clone = function(deep, falseArray/*check*/) {
var type = Object.prototype.toString.call(this).match(/^$object (.+?)$$/)[1]; /*var falseArray; if(check) { falseArray = (Object.keys(this).length - this.length); }*/ //takes around 400ms additional at 500k array to check if it has additional properties, just pass it as argument decide if oy switch (type) { case "Array" : var clone = []; if (!falseArray) { if (!deep) clone = this.concat(); else this.forEach(function(e) { if(typeof e !== "undefined" && e !== null) clone.push((typeof e !== "object"?e:e.clone((typeof deep == "boolean"?deep:(deep-1))))); else clone.push(""); }); } else {// Variable is an 'Array' but has an extra propertie e.g: var arr = [1,2,3]; arr.a = "b" //its the slowest possibility but normally Objects would be used for (var prop in this ) { clone[prop] = this[prop]; } } break; case "Object": var clone = {}; if (!deep) { for (var prop in this) { clone[prop] = this[prop]; } } else { for (var prop in this) { if(typeof this[prop] !== "undefined" && this[prop]!== null) clone[prop] = (typeof this [prop] !== "object"?this[prop]:this[prop].clone((typeof deep == "boolean"?deep:(deep-1)))); else clone[prop] = ""; } } break; default : var clone = this.valueOf(); break; } return clone; }; Object.defineProperty(Object.prototype, "clone", { enumerable : false });  And here are some links: I've changed it a little bit to have it in Array.Prototype and Object.prototype to avoid the switch for the Object type, but I can't tell if it makes a difference. Object.prototype.clone = function(deep, falseAray) { var type = Object.prototype.toString.call(this).match(/^$object (.+?)$$/)[1];
var test = this;
if (!type == "Object") {
return this.valueOf;
}
/*var falseArray;
if(check) {
falseArray = (Object.keys(this).length - this.length);
}*/ //takes around 400ms additional at 500k array to check if it has additional properties, just pass it as argument
var clone = {};
if (!deep) {
for (var prop in this) {
clone[prop] = this[prop]
}
} else {
for (var prop in this) {
if ( typeof this[prop] !== "undefined" && this[prop] !== null)
clone[prop] = ( typeof this[prop] !== "object" ? this[prop] : this[prop].clone(( typeof deep == "boolean" ? deep : (deep - 1))));
else
clone[prop] = "";
}
}
return clone;
};
Object.defineProperty(Object.prototype, "clone", {
enumerable : false
});

Array.prototype.clone = function(deep, falseArray) {
var test = this;
/*var falseArray;
if(check) {
falseArray = (Object.keys(this).length - this.length);
}*/ //takes around 400ms additional at 500k array to check if it has additional properties, just pass it as argument
var clone = [];
if (!falseArray) {//For me around 15-20ms at [500k]
if (!deep)
clone = this.concat();
else
this.forEach(function(e) {
if ( typeof e !== "undefined" && e !== null)
clone.push(( typeof e !== "object" ? e : e.clone(( typeof deep == "boolean" ? deep : (deep - 1)))));
else
clone.push("");
});
} else {// Variable is an 'Array' but has an extra propertie e.g: var arr = [1,2,3]; arr.a = "b" //its the slowest possibility but normally Objects would be used

for (var prop in this ) {//around 630 - 700ms
clone[prop] = this[prop];
}
}
return clone;
};
Object.defineProperty(Array.prototype, "clone", {
enumerable : false
});


I tested it in Titanium where some code creates tables from JSON Objects (1000 rows with 29 properties per row (which contain array objects and primitive and null Values). The clone method copies the JSON object.

The first needed:

1: 400ms , 2: 361ms , 3: 314ms , 4: 317ms , 5: 318ms

The second needed:

1: 294ms , 2: 329ms , 3: 298ms , 4: 298ms , 5: 299ms

(Complete execution time, not only the copying)

I tried to change this:

(typeof deep == "boolean" ? deep : (deep - 1))


to

(deep - 1)


and call the method with x.clone(Infinity)instead of x.clone(true) to save one if clause per level of depth, but it turned out the execution speed varies from 300 to 370ms. Why is subtracting from infinity that slow/unstable compared to a type check through + a if clause? (its type is a number, so I thought it might do simply nothing if subtracting/adding etc sth to infinity).

It seems this is a problem for Titanium, benchmarks on Jsperf are around the same for both. I also tested both Codes with an 2k array where each entry contains arrays to a depth of 500. But the speed of both is the same. Is the cause this the branch prediction?

• Why are you extending Object.prototype? Jul 12 '12 at 22:47
• to be able to invoke the method to clone directly from any Object like var y = x.clone() Jul 12 '12 at 23:38

One thing I noticed was that you are using advanced (ECMAScript 5) parts of JavaScript - this will not work in old browsers, such as IE8 (I don't know where you are planning on using this).

• I would mainly use it in titanium (if not only) therefore i don't have to worry about browser compatibility but it would be nice to get some more speed out of it, when processing big json Objects (and of course i would be happy to learn javascript a little better ) Jul 17 '12 at 17:53

When you say "big JSON objects", do you mean a string containing JSON?

If I were you, I'd compare your method with serializing to a JSON string and deserializing from that string (that's cloning, too). As it is probably implemented in native code and directly supported by the VM, it should be really fast. I expect it to beat anything you can write - and it's way more compact, too. But I didn't test it, YMMV. Just consider and benchmark it.

• i tried it right at the beginning when i wrote this ,and serializing/deserializing was way slower for me ( chrome ) Aug 20 '12 at 14:34
• Did you use the native JSON object or did you import a JS-version?
– Arne
Oct 2 '12 at 7:16
• jsperf.com/deep-clone-test/3 for me its 0.58 (clone method) vs 0.26 Ops/sec (serializing/deserializing) with JSON.parse/stringify Oct 9 '12 at 9:53
• Ok, it was worth a shot. Sorry :-)
– Arne
Oct 10 '12 at 7:43
• that sure is right, Thx anyway for the suggestion:) Oct 10 '12 at 15:54