/** * @name deepClone - Node.js function for deep cloning objects * * @author Kumar Abhirup · 🐦 Twitter: @kumar_abhirup * * @param {object} objectToClone * * @returns object | null | undefined | Error */ function deepClone(objectToClone) { if (!objectToClone) return objectToClone // Check for null, undefined, 0 and false // Throw an error if `objectToClone` is not an array or object if (typeof objectToClone !== 'object') throw new Error(`Expected argument of type 'object' but received a '${typeof objectToClone}'`) // To support older node versions which might not have support for Array.isArray if (typeof Array.isArray === 'undefined') { Array.isArray = function (obj) { return Object.prototype.toString.call(obj) === '[object Array]' } } let node // This is so that the function understands the difference between Arrays, Objects, and Regular Expressions. const clonedObject = (() => { if (Array.isArray(objectToClone)) return [] else if (objectToClone instanceof RegExp) return objectToClone // If it is a RegExp, just return that instead of an empty object else return {} })() /** * Iterates through `objectToClone` and generates the `clonedObject`. * If while iterating, it finds another object, it deep clones it again. */ for (const key in objectToClone) { node = objectToClone[key] clonedObject[key] = (() => { // Check for `node` if (!node) return node else if (typeof node === "object") return deepClone(node) // This is a recursion else return node })() } return clonedObject } // Export it so that you can unit test this function module.exports = deepClone // Use the function const objectToClone = { name: "Paddy", address: { town: "Lerum", country: "Sweden" } } const clonedObject = deepClone(objectToClone) console.log(clonedObject)