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 testet until now, but for JSON objects it seemed kind of slow to me,
And 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
Thanks for your Reviews, here is the Code:
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
Link to JS Bin example
Link to jsPerf
update:
Well i 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
});
Link to JS Bin example: http://jsbin.com/abotoh/4/edit#javascript,html
Link to jsPerf http://jsperf.com/deepclone-test/5
Ok, i tested it in Titanium where some Code creates Tables from JSON Objects, (1000Rows with 29 Properties per Row (which contain Arrays Objects and Primitive and null Values);
The Clone method copys the JSON object.
The first Code needed:
1: 400ms , 2: 361ms , 3: 314ms , 4: 317ms , 5: 318ms
And the second needed:
1: 294ms , 2: 329ms , 3: 298ms , 4: 298ms , 5: 299ms
(Complete Execution Time, not only the copying);
Update2:
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 substracting from Infinity
that slow/unstable compared to a type check through + a if clause? (well its type is number, i thought it might do simply nothing if substracting/addin etc sth to Infinity)
It seems this is a problem of 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 ?
Thanks for your Help!
Object.prototype
? – Bill Barry Jul 12 '12 at 22:47var y = x.clone()
– C5H8NNaO4 Jul 12 '12 at 23:38