This short article introduces a method that may be used to create a 'deep-copy' of an javascript object. You might ask: 'Wherefore do we need this?' ... Answer: 'Only variable-values of the basic data-types string, int, float, boolean and to make the confusion perfect :) functions too! are passed by value, all others are passed by reference.' This means, when you create an object a, like in the code below, and you assign object a to variable b then you will pass the object a by reference. That results in the fact, that when you assign a new value to b.foobar, a.foobar will be changed accordingly. To pass it by value, what you can imagine as a (deep-)copy of object a, we have to use a function that recursivly copies the values of any datastructure inside of object a to object b.
-
// example object that might be cloned
-
var a = {
-
foo : { test: 1, test1: 2 },
-
bar : function(a) { alert(a) },
-
foobar: 'foobar1',
-
arr : [1, [8, 9], {1: 1, 2: 2}, 4]
-
};
-
-
/**
-
* function clone_obj deep-clones an js-object
-
*
-
* @param obj javascript-object
-
* @return c cloned javascript-object
-
*/
-
function clone_obj(obj) {
-
if (typeof obj !== 'object' || obj == null) {
-
return obj;
-
}
-
-
var c = obj instanceof Array ? [] : {};
-
-
for (var i in obj) {
-
var prop = obj[i];
-
-
if (typeof prop == 'object') {
-
if (prop instanceof Array) {
-
c[i] = [];
-
-
for (var j = 0; j < prop.length; j++) {
-
if (typeof prop[j] != 'object') {
-
c[i].push(prop[j]);
-
} else {
-
c[i].push(clone_obj(prop[j]));
-
}
-
}
-
} else {
-
c[i] = clone_obj(prop);
-
}
-
} else {
-
c[i] = prop;
-
}
-
}
-
-
return c;
-
}
-
-
// usage: we clone object a to object b
-
var b = clone_obj(a);
-
Note: Why can't we copy dom-nodes with that function? Answer: dom-nodes contain references to its parent- and child-objects etc. When copying this with the above method we will get an error: 'too much recursion' ... because when copying a parent object we come to a child of that and from there to its parent and so on ... for cloning dom-nodes we simply may use the cloneNode() dom-method.
testers needed ;) ... i think it works the way it should ... but may be I've overlooked something?
testing-help: when testing in firebug console the test scenario could be for example:
- var a = {
-
foo : { test: 1, test1: 2 },
-
bar : function(a) { alert(a) },
-
foobar: 'foobar1',
-
arr : [1, [8, 9], {1: 1, 2: 2}, 4]
-
};
-
-
var c = a;
-
c.foobar = 'new test';
-
-
function clone_obj(obj) {
-
if (typeof obj !== 'object' || obj == null) {
-
return obj;
-
}
-
-
var c = obj instanceof Array ? [] : {};
-
-
for (var i in obj) {
-
var prop = obj[i];
-
-
if (typeof prop == 'object') {
-
if (prop instanceof Array) {
-
c[i] = [];
-
-
for (var j = 0; j < prop.length; j++) {
-
if (typeof prop[j] != 'object') {
-
c[i].push(prop[j]);
-
} else {
-
c[i].push(clone_obj(prop[j]));
-
}
-
}
-
} else {
-
c[i] = clone_obj(prop);
-
}
-
} else {
-
c[i] = prop;
-
}
-
}
-
-
return c;
-
}
-
-
var b = clone_obj(a);
-
b.foobar = 'test';
-
b.bar = function(a) { alert(a + a) };
-
-
console.info(a.toSource());
-
console.info(b.toSource());
-