Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Post History
By "deeply clone", I assume you mean "also make copies of whatever nested structures the object might have". And for those, I guess libraries like Lodash are more reliable and appropriate if you wa...
Answer
#1: Initial revision
By "deeply clone", I assume you mean "_also make copies of whatever nested structures the object might have_". And for those, I guess libraries like [Lodash](https://lodash.com/docs/4.17.15#cloneDeep) are more reliable and appropriate if you want to save some work. Of course for simple cases (such as arrays containing only numbers, strings, or even nested arrays/objects whose values are numbers and strings), approaches such as `JSON.parse(JSON.stringify(array))` are enough. Actually, if the array contains only "simple" types such as numbers and strings and has no nested structures, `array.slice()` is enough to make a copy. But for more complicated cases, Lodash can save you a lot of work. JSON approach, for instance, doesn't work if the array contains a function or some other objects, such as a `Date`. And the `map` solution suggested [in the other answer](https://software.codidact.com/posts/285500/285502#answer-285502) doesn't work as well, as it converts nested arrays to objects: ```javascript var x = [ 1, 2, {a: 3} ]; var array = [ function () { console.log('hi') }, new Date(), x ]; function checkClone(clone, msg) { console.log(`------\n${msg}`); console.log(clone); // check function console.log('is function?', typeof clone[0] === 'function'); // check Date console.log('is Date?', Date.prototype.isPrototypeOf(clone[1])); // check array if (Array.isArray(clone[2])) { // add element to nested array, and check if original array is modified clone[2].push(3); console.log('original array', x); } else { console.log('nested element is not an array'); } } checkClone(_.cloneDeep(array), 'Lodash'); checkClone(array.map(e => ({ ...e })), 'map'); checkClone(JSON.parse(JSON.stringify(array)), 'JSON'); ``` I've created a function that receives a cloned array and checks what happened with its elements. The output is: ```none ------ Lodash [ [Function (anonymous)], 2022-01-07T17:40:25.897Z, [ 1, 2, { a: 3 } ] ] is function? true is Date? true original array [ 1, 2, { a: 3 } ] ------ map [ {}, {}, { '0': 1, '1': 2, '2': { a: 3 } } ] is function? false is Date? false nested element is not an array ------ JSON [ null, '2022-01-07T17:40:25.897Z', [ 1, 2, { a: 3 } ] ] is function? false is Date? false original array [ 1, 2, { a: 3 } ] ``` As we can see, only Lodash correctly copied everything, keeping the function and the `Date`. JSON solution didn't keep those (the function was ignored, and the `Date` was converted to a string representation). `map` solution is even worse, because it also converted the nested array to an object. --- Another drawbacks: JSON doesn't handle cyclic references and `undefined` values will be changed to `null`. `map` solution can handle cycles, but `undefined` is changed to `{}` (empty object). Neither works with custom classes (Lodash handles all those cases correctly, though). If you're cloning "simple" objects (no functions or any types other than numbers and strings, no `null`/`undefined`, etc), I guess the JSON approach should be fine. If you have anything else (`Date`, `BigInt`, `Symbol`, your custom class, etc), I'd say to go with Lodash (or any other library), which will be easier than writing your own clone function (just to have an idea of the difficulty, [take a look at Lodash source code](https://github.com/lodash/lodash/blob/2da024c3b4f9947a48517639de7560457cd4ec6c/.internal/baseClone.js)). --- But if you have just one or another element that's not handled by `JSON.stringify` and `JSON.parse`, maybe you don't need to import a whole library just for that. You could only add a custom serialization and deserialization method for this element. For example, if the only "different", non-JSON-supported type is a `Date`: ```javascript // custom serialization for Dates Date.prototype.toJSON = function() { return '__date__:' + this.getTime(); } // custom deserialization for Date (anything else is treated as is) function deserialize(key, val) { if (val && typeof val === 'string' && val.indexOf('__date__:') === 0) { return new Date(parseInt(val.slice(9))); } return val; } var array = [1, 'abc', new Date()]; console.log(JSON.parse(JSON.stringify(array), deserialize)); ``` But if you need to handle lots of different types (such as functions, custom classes, etc), this method can become tedious. In this case, you could evaluate if it's worth writing your own functions, or use a library like Lodash.