During the development process, you often encounter the time when you need to copy the object, because the object is a reference data type and the object's address is recorded in the assignment process, so if multiple variables point to the same memory address and change the properties of one variable, all variables will be affected, and deep copy is required in the object copying process.
1 Define a variable
var copy;
Define a variable without assignment, because the type of copy is not necessarily an object, it may be an array or something else.
2 Consider basic data types
if (null == values || "object" != typeof values) return values;
If the type is null,undefined, string, boolean, numberNumber returns the original value directly.
3 Consider Date
Date is used to create a time object and is essentially an object. Therefore, the copy process also needs to get rid of the original object reference address. Here, you need to re-create a date instance and keep it consistent with the original object value.
if (values instanceof Date) { copy = new Date(); copy.setTime(values.getTime()); return copy; }
4 Consider Array
An object's attributes may also be arrays and arrays may also be objects, and if copied directly, the reference to the original array will remain. So you also need to create a new array here. Since elements in an array can also be of any data type, recursion can be used here:
if (values instanceof Array) { copy = []; for (var i = 0, len = values.length; i < len; i++) { copy[i] = deepClone(values[i]); } return copy; }
5 Considerations
If the value is still an object, each key needs to be traversed, the for in traversal used here. The value of an object can also be any data type, so recursion is used here. During traversal, you see a piece of code: values.hasOwnProperty(attr). This is done for performance reasons, because the for-in loop traverses not only the properties of the object itself, but also the enumerable properties on the prototype, which in turn avoids the properties on the prototype.
if (values instanceof Object) { copy = {}; for (var attr in values) { if (values.hasOwnProperty(attr)) copy[attr] = deepClone(values[attr]); } return copy; }
Considering circular references, there are circular references to the following writings: if you copy directly using the above method, you will get an error that exceeds the maximum execution stack.
var obj = {}; obj.a = new Date('2020-01-27'); obj.b = obj;
You can use data caching to solve circular reference problems. var map = new WeakMap() can accept only objects, and value can be any value. When you encounter the code below, a circular reference object exists, and the code does not need to be executed down, but simply returns the stored data.
if(map.has(value)) { return map.get(value); }
function wrapDeepClone(value) { var map = new WeakMap() function deepClone(value) { var copy, existObj; // key can only be an object type if(!value || typeof value !== 'object') return value; if(value instanceof Date) { copy = new Date(); copy.setTime(value.getTime()); return copy; } if(map.has(value)) { return map.get(value); } if(value instanceof Array) { copy = []; map.set(value, copy); for(var i = 0; i < value.length; i++) { copy[i] = deepClone(value[i]); } return copy; } if(value instanceof Object) { copy = {}; map.set(value, copy); for(var key in value) { if(value.hasOwnProperty(key)) { copy[key] = deepClone(value[key]) } } return copy; } } return deepClone(value) } var copyObj = wrapDeepClone(obj); console.log(copyObj);