http://www.mikitamanko.com/blog/2013/05/12/how-to-clone-an-object-in-javascript/
What is the most efficient way to clone an object in JavaScript?
Here is the wrong way that will not work properly
var obj1 = { a: 1, b: { c: {d: 2}, e: 3}},
obj2 = {};
console.dir(obj1);
for(var key in obj1) {
if(obj1.hasOwnProperty(key)) {
obj2[key] = obj1[key];
}
}
console.dir(obj2); // seems the same object, but NOT
obj2 will look the same as an obj1, but it’s not a clone (because we just copied references), let’s prove that:
var obj1 = { a: 1, b: { c: {d: 2}, e: 3}},
obj2 = {};
for(var key in obj1) {
if(obj1.hasOwnProperty(key)) {
obj2[key] = obj1[key];
}
}
obj1.b.c.d = 42; // Changed obj1
console.dir(obj2); // OOPS, changes of obj1 has been applied to obj2
So it’s not a clone.
Here is the most efficient “handmade” way to clone the object:
var obj1 = { a: 1, b: { c: {d: 2}, e: 3}},
obj2 = {};
obj2 = JSON.parse(JSON.stringify(obj1));
obj1.b.c.d = 42; // Changed obj1
console.log(obj1);
console.dir(obj2); // cool, obj2 still the same
BTW, in production code it’s recommended to use this way:
var obj1 = { a: 1, b: { c: {d: 2}, e: 3}},
obj2 = {};
obj2 = $.extend(true, {}, obj1); // jQuery extend method
obj1.b.c.d = 42; // Changed obj1
console.log(obj1);
console.dir(obj2); // cool, obj2 still the same
I think that it is the best way to clone the object (described above)
Here is the list of all possible ways to clone the object:
// jQuery deep copy:
var newObject = jQuery.extend(true, {}, oldObject); // 76% slower
// JSON
var newObject = JSON.parse(JSON.stringify(oldObject)); // 12% slower
// jQuery copy (not deep)
var newObject = jQuery.extend({}, oldObject); // 24% slower
// simple clone function
var newObject = clone(oldObject); // fastest way, first function, that will copy only references (seems to be completely wrong way)
// ES5 Object.clone
var newObject = Object.clone(oldObject); // 85% slower
Here is the link on benchmark http://jsperf.com/cloning-an-object/2
So, the best production way to clone the object is still jQuery deep copy (not due to the benchmarks, but it’s the most safe and recommended way)
Let’s dig into this, and take a look under the hood. Here it the source code of jQuery extend:
https://github.com/jquery/jquery/blob/master/src/core.js#L265
Here is the “core” part
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
// Recurse if we're merging plain objects or arrays
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];
} else {
clone = src && jQuery.isPlainObject(src) ? src : {};
}
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );
// Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
So, let’s take a look at fully “handmade” function “clone”
Here is simplified similar function (but not the same)
<span style="font-size:14px;">function extend (target, other) {
target = target || {};
for (var prop in other) {
if (typeof source[prop] === 'object') {
target[prop] = extend(target[prop], source[prop]);
} else {
target[prop] = source[prop];
}
}
return target;
}</span>
P.S.
somewhere I saw this way to clone the object
eval(uneval(o));
Please, do not even think about using of this. Eval is completely evil (Douglas Crockford will help you to find out the reason)