I've made this function for to get a deep copy (recursive copy) of objects. => Sub-objects aren't references to the sub-objects of the original object. Instead they are objects on their own.
Here's my code ...
Attention: Most of it are test data and an additional test-function.
// ----- Test data ---------------------
var swapi = [ {
"name": "Luke Skywalker",
"height": "1.72 m",
"mass": "77 Kg",
"hair_color": "Blond",
"skin_color": "Caucasian",
"eye_color": "Blue",
"birth_year": "19 BBY",
"gender": "Male",
"homeworld": "http://swapi.co/api/planets/1/",
"films": [
"http://swapi.co/api/films/1/",
"http://swapi.co/api/films/2/",
"http://swapi.co/api/films/3/"
],
"species": [
"http://swapi.co/api/species/1/"
],
"vehicles": [
"http://swapi.co/api/vehicles/14/",
"http://swapi.co/api/vehicles/30/"
],
"starships": [
"http://swapi.co/api/starships/12/",
"http://swapi.co/api/starships/22/"
],
"created": "2014-12-09T13:50:51.644000Z",
"edited": "2014-12-10T13:52:43.172000Z",
"url": "http://swapi.co/api/people/1/"
},
{
"name": "C-3PO",
"height": "167",
"mass": "75",
"hair_color": "n/a",
"skin_color": "gold",
"eye_color": "yellow",
"birth_year": "112BBY",
"gender": "n/a",
"homeworld": "http://swapi.co/api/planets/1/",
"films": [
"http://swapi.co/api/films/5/",
"http://swapi.co/api/films/4/",
"http://swapi.co/api/films/6/",
"http://swapi.co/api/films/3/",
"http://swapi.co/api/films/2/",
"http://swapi.co/api/films/1/"
],
"species": [
"http://swapi.co/api/species/2/"
],
"vehicles": [],
"starships": [],
"created": "2014-12-10T15:10:51.357000Z",
"edited": "2014-12-20T21:17:50.309000Z",
"url": "http://swapi.co/api/people/2/"
},
{
"name": "R2-D2",
"height": "96",
"mass": "32",
"hair_color": "n/a",
"skin_color": "white, blue",
"eye_color": "red",
"birth_year": "33BBY",
"gender": "n/a",
"homeworld": "http://swapi.co/api/planets/8/",
"films": [
"http://swapi.co/api/films/5/",
"http://swapi.co/api/films/4/",
"http://swapi.co/api/films/6/",
"http://swapi.co/api/films/3/",
"http://swapi.co/api/films/2/",
"http://swapi.co/api/films/1/",
"http://swapi.co/api/films/7/"
],
"species": [
"http://swapi.co/api/species/2/"
],
"vehicles": [],
"starships": [],
"created": "2014-12-10T15:11:50.376000Z",
"edited": "2014-12-20T21:17:50.311000Z",
"url": "http://swapi.co/api/people/3/"
}
];
// --- Start : THE ACTUAL FUNCTION ---------------
/** Supplies a deep copy of an object.
*
* @param { Object } obj - The object to copy.
* @return { Object } - Copy of the given object.
* @throws { Object } When given object is not
* of type object.
*
* -- Usage example -------------------------------
* var copyOfObj = getDeepCopy({ a: 3, b: 5 });
*/
function getDeepCopy(obj) {
var ret;
if (typeof obj !== 'object') {
throw {
message: 'Object expected as parameter.'
}
}
ret = Array.isArray(obj) ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
let current = obj[key];
if (typeof current !== 'object') {
ret[key] = current;
} else {
ret[key] = getDeepCopy(current);
}
}
}
return ret;
}
// --- End : THE ACTUAL FUNCTION ------------------
// -------- TESTING --------------------------------
function testGetDeepCopy(original, copy) {
var originalLength = Object.keys(original).length;
var copyLength = Object.keys(copy).length;
var errorMessages = '';
if (originalLength !== copyLength) {
errorMessages += 'Count properties original is ' +
originalLength + ' but count of properties copy is ' +
copyLength + '.'
}
for (var prop in original) {
if (typeof original[prop] !== 'object') {
if (original[prop] !== copy[prop]) {
errorMessages += ' Original value is ' + original[prop] +
' but copy value is ' + copy[prop] + '.';
}
} else {
if (original[prop] === copy[prop]) {
errorMessages +=
' Original and copy reference is same object.';
} else {
let tmp = testGetDeepCopy(original[prop], copy[prop]);
if (tmp !== 'Test passed.') {
errorMessages + ' ' + tmp;
}
}
}
}
if (!errorMessages) {
return 'Test passed.';
} else {
return errorMessages.trim();
}
}
try {
swapi.forEach(function(swObj, i) {
console.log('Test %s (%s) : %s',
i,
swObj.name,
testGetDeepCopy(swObj, getDeepCopy(swObj)));
});
} catch (e) {
console.log(e.message);
}
I leave it in there because I would be interested in:
Hints and comments to the actual function: Would it work as expected? Could it be improved. Or would be better to take a complete different approach?
Documentation: Done a proper way? Can one understand at once how the function has to be used? Or must it be improved?
Testing: Does it cover everything what is important? Possible improvements?
Looking forward to read your answers.
var deepCopy = JSON.parse(JSON.stringify(source))
for the simple data shown in your code. Do some benchmarks to compare the speed of your solution. \$\endgroup\$