Js contains two different types of data values: primitive data types and reference data types. The concepts of deep copy and shallow copy only exist in reference data types. For reference types, shallow copy copies the pointer to the object heap memory, while deep copy copies all the properties of the object to a new object. If a property of the original object still references another object, then that referenced object needs to be deep copied as well, with recursion. There is no concept of deep copy or shallow copy for primitive data types. If the value of a primitive data type variable is assigned to another variable, the new variable's value is a copy of the original variable's value, not a reference. If one must consider the concepts of deep and shallow copy, the copy of primitive data types can be understood as a deep copy by value.
To implement shallow copy using native methods, one can use {...obj} and Object.assign({}, obj), where {...obj} primarily uses the spread operator to construct a literal object by expanding the object expression, achieving shallow copy. Object.assign({}, obj) performs a copy of enumerable properties to the target object and returns the target object. Whether Object.assign performs shallow copy or deep copy depends on how one understands the concepts. If one, like in this article, believes that only reference types have the concepts of deep and shallow copy, then Object.assign is a shallow copy. If one believes that primitive data types also have the concepts of deep and shallow copy, then as mentioned earlier, the copy of primitive data types can be understood as a deep copy by value, so the claim that Object.assign is a deep copy for the first layer and a shallow copy for subsequent layers is also valid.
To implement deep copy using native methods, one mainly uses JSON.parse() and JSON.stringify(). First, the object is serialized into a JSON string, and then the JSON string is deserialized into an object. This method is efficient but has some issues. It cannot achieve deep copy for objects with circular references. When the object being copied contains properties of Date objects, this approach converts the time object into a string. Similarly, for properties of RegExp objects and Error objects, this approach results in an empty object. It ignores properties of function objects, undefined, and Symbol values. For properties of NaN, Infinity, and -Infinity, the result is converted to null.
functionshallowCopy(target, origin){return Object.assign(target, origin);}functiondeepCopy(target, origin){var originDeepCopy =JSON.parse(JSON.stringify(origin));return Object.assign(target, originDeepCopy);}// Shallow copy test: copy properties from origin to targetvar target ={}var origin ={// a property as a reference typea:{aa:1}}shallowCopy(target, origin);console.log(target, origin);// {a: {aa: 1}} {a: {aa: 1}}origin.a.aa =11;console.log(target, origin);// {a: {aa: 11}} {a: {aa: 11}}// Deep copy test: copy properties from origin to targetvar target ={}var origin ={// a property as a reference typea:{aa:1}}deepCopy(target, origin);console.log(target, origin);// {a: {aa: 1}} {a: {aa: 1}}origin.a.aa =11;console.log(target, origin);// {a: {aa: 1}} {a: {aa: 11}}
For shallow copy, one only needs to assign all enumerable properties of the copied object.
For deep copy, one must assign primitive data types and then recursively process object properties.
functionshallowCopy(target, origin){for(let item in origin) target[item]= origin[item];return target;}```javascript
functiondeepCopy(target, origin){for(let item in origin){if(origin[item]&&typeof(origin[item])==="object"){// Only simple processing is done for Object Array Date RegExp objectsif(Object.prototype.toString.call(origin[item])==="[object Object]"){ target[item]=deepCopy({}, origin[item]);}elseif(origin[item]instanceofArray){ target[item]=deepCopy([], origin[item]);}elseif(origin[item]instanceofDate){ target[item]=newDate(origin[item]);}elseif(origin[item]instanceofRegExp){ target[item]=newRegExp(origin[item].source, origin[item].flags);}else{ target[item]= origin[item];}}else{ target[item]= origin[item];}}return target;}// Shallow copy test: shallow copy properties from origin to targetvar target ={}var origin ={// Property a is a reference typea:{aa:1}}shallowCopy(target, origin);console.log(target, origin);// {a: {aa: 1}} {a: {aa: 1}}origin.a.aa =11;console.log(target, origin);// {a: {aa: 11}} {a: {aa: 11}}// Deep copy test: deep copy properties from origin to targetvar target ={}var origin ={// Property a is a reference typea:{aa:1,bb:{bbb:1},cc:[1,{ccc:1}],dd:newDate().getTime(),ee:/./g}}deepCopy(target, origin);console.log(target, origin);/*
a: { a: {
aa: 1 aa: 1
bb: {bbb: 1} bb: {bbb: 1}
cc: [1, {ccc: 1}] cc: [1, {ccc: 1}]
dd: 1390318311560 dd: 1390318311560
ee: /./g ee: /./g
} }
*/origin.a.aa =11;origin.a.bb.bbb =11;origin.a.cc[0]=11;origin.a.cc[1].ccc =11;origin.a.dd =newDate().getTime();origin.a.ee =/./gi;console.log(target, origin);/*
a: { a: {
aa: 1 aa: 11
bb: {bbb: 1} bb: {bbb: 11}
cc: [1, {ccc: 1}] cc: [11, {ccc: 11}]
dd: 1390318311560 dd: 1390318792391
ee: /./g ee: /./gi
} }
*/