The object copies of native js are all shallow copies. If you need deep copies, you need to do some manual operations
Using json to serialize and deserialize
Example:
let obj = { name: 'lizitao', msg: { age: '2' } }; let cp = JSON.parse(JSON.stringify(obj)); console.log(cp);
Advantage: very simple to write
Disadvantage: too many limitations. Because only those data types supported by json are supported. Functions, undefined, regular, etc. are not supported. In case of ring structure, an error will be reported:
var obj = { a: undefined }; console.log(JSON.parse(JSON.stringify(obj))) // {} // Attribute a is automatically ignored
JSON.stringify will check whether there is a ring, and throw an error if there is one
var obj = {}; obj.child = obj; JSON.stringify(a) // Uncaught TypeError: Converting circular structure to JSON
So we can only use a more complex way to realize deep copy by returning
The first version (prototype), which can copy simple objects
const clone = function(source){ if(source instanceof Object){ let result = {} for (const key in source) { result[key] = clone(source[key]) } return result } else { return source } }
First, judge whether it is an object. If it is not an object, return its value directly. If it is an object, create a new empty object {}, and copy the properties to it. Note that property copying calls the clone function recursively: result[key] = clone(source[key]), so as to ensure that each layer is a deep copy!.
However, it only judges whether the object is an object, and assumes that the object is in the form of {name: value}. If the object is an array, a function, a date, and so on, it won't work. Therefore, it is necessary to determine which type of object the object is, and initialize the result according to the specific type of the object, in the form of:
if(source instanceof Object){ //... if(source instanceof Array){ //... } else if(source instanceof Function){ //... } else if(source instanceof Date){ //... } // Omit many else if, and the more detailed the judgment is, the more object types are supported else { //... } } else { //... }
So we wrote the second edition according to this idea
The second version supports multiple types of objects
const clone = function(source){ if(source instanceof Object){ let result = null if(source instanceof Array){ result = [] } else if(source instanceof Function){ result = function(){ return source.apply(this, arguments) } } else if (source instanceof Date) { result = new Date(source); } else { result = {} } for (const key in source) { result[key] = this.clone(source[key]) } return result } else { return source } }
The last problem to be solved is that the object is a ring. The basic idea is to use an array to store all the copied objects. Before each call, judge whether the object has been copied or not, and return directly if it has been copied.