concept
The concept of deep and shallow copy is primarily for reference type values.
In memory, the name of the reference data is stored in stack memory (where the value is the address of the reference type value), and the real value of the reference type is stored in heap memory. So the stack memory provides a reference type address to point to the value in the heap memory.
There is another way to think about it: shallow copy is copying a layer of references at the deep object level (for-in loop object properties or objects); Deep copy is the copying of multiple layers of data at each level.
Shallow copy
Shallow copy: B copies the reference address of A, but not the value of A, so both A and B point to the value of a’s heap memory.
Deep copy: not only does B copy the contents of A, but ALSO B has dedicated memory in the heap for it.
Implement shallow copy:
1. For -in loop layer 1, object properties are still objects
function simplyCopy(obj1){ var obj2 = Array.isArray(obj1) ? [] : {}; for(let i in obj1){ obj2[i] = obj1[i] } return obj2; } var obj1 = { a : 1, b : 2, c : { d : 3 } } var obj2 = simplyCopy(obj1); obj2.a = 2; obj2.c.d = 4; console.log(obj1.a); console.log(obj2.a); console.log(obj1.c.d); console.log(obj2.c.d);Copy the code
Output:
Its implementation process can be seen as:
So if you change d in obj2.c, obj1.c.d will also change; But if you change property A, it doesn’t change.
If the object is full of primitive-type values, or nested multiple times, looping through multiple layers can actually be considered a deep copy.
function simplyCopy(obj1){ var obj2 = Array.isArray(obj1) ? [] : {}; for(let i in obj1){ obj2[i] = obj1[i] } return obj2; } var obj1 = { a : 1, b : 2 } var obj2 = simplyCopy(obj1); console.log(obj2 == obj1);Copy the code
The output is: false
So this is more consistent with the other way we talked about it.
Add the following distinction between for-in and for-of
1. For-in is used for traversal of object attributes. If for-in is used in an object, an error message is displayed indicating that the object is not iterable.
2. In an array, a for-in loop reads the key and a for-of retrieves the value.
3. In set and MAP structures, of is generally used to iterate through the loop to get the value;
4. Use for-of in other array-like objects such as strings, DOM NodeList objects, and arguments objects
Disadvantages of for-in:
1. Index The index is a string number (note that it is not a number) and cannot be directly used for geometric operations.
2. The traversal order may not be in the internal order of the actual array (possibly in random order).
3. Using for-in iterates through all enumerable properties of a set, including stereotypes.
Why can’t for-of traverse an object?
Because for of traversal relies on the Iterator. Iterators are used to provide a method that does not depend on index values. For-of cannot iterate over an object because there is no symbol. iterator method in the object. Arrays 2) Strings 3) Map4) Set5) Arguments6) Typed Arrays7) Generators already have iterators built in, so they can be iterated for of.
2. The Object. The assign method
The object.assign () method is used to assign the values of all enumerable properties from one or more source objects to target objects. It will return the target object. If an attribute in the target object has the same key, the attribute is overwritten by an attribute in the source object. Properties of subsequent source objects similarly override properties of previous source objects.
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget =Object.assign(target, source);
console.log(target);
// expected output: Object { a: 1, b: 4, c:
5 }
Copy the code
console.log(returnedTarget);
// expected output: Object { a: 1, b: 4, c: 5 }
Object.assign() copies (enumerable) property values. If the source value is a reference to an object, it simply copies its reference value.
var obj = {
a: 1,
b: 2
}
var obj1 = Object.assign(obj);
obj1.a = 3;
console.log(obj.a) // 3
The replication process is shown as follows:
But if you give it an empty object to store obJ, the result is different.
var obj1 = Object.assign({},obj);
obj1.a = 3;
console.log(obj.a)
Output: 1
The difference is whether an empty object with memory is allocated before it runs.
If obj still has a reference type value, as shown in the following code:
var obj = {
a: 1,
b: 2,
c : {
d:3
}
}
var obj1 = Object.assign({},obj);
obj1.a = 3;
obj1.c.d = 4;
console.log(obj,obj1)
The output is:
This is similar to for-in, in that the base type value of OBj has its own memory and value, but the reference type value points to the heap memory.
3. Direct assignment
Let a =,1,2,3,4 [0],
b=a;
console.log(a===b);
a[0]=1;
console.log(a,b);
Output: true, [1,1,2,3,4], [1,1,2,3,4]
Therefore, we can directly draw a conclusion that basic type values can be copied directly and have their own memory, but reference type values are copied in the first layer, and need to be further copied, which is the origin of shallow copy.
### shallow copy ##### 4. Concat of arrays,slice concat is used to concatenate two arrays, does not modify the existing array, returns a new array. However, when arrays are nested, it can be found that from the second layer, the relationship is still a reference, and both concat and slice are shallow copies. # # # # # 5. * *... The ** expansion operator makes a deep copy of the first layer of the object, and then copies the reference values.Copy the code
Deep copy
Implementing deep copy:
1. Copy all hierarchy attributes recursively.
Object creation and object assignment are implemented for each layer of data:
- Determine the type. Simple types return directly
- For circular references, the copy checks whether the object already exists in the storage space, and returns the object if it does
- The reference type is copied recursively until it is the original type
Determine if its child is an object, if so, continue recursion, if not simply copy its value
function deepClone(obj){ let objClone = Array.isArray(obj)? [] : {}; If (obj && typeof obj==="object"){for(key in obj){if(obj. HasOwnProperty (key)){// Determine if ojb child is an object, if so, If (obj[key]&&typeof obj[key] ==="object"){objClone[key] = deepClone(obj[key]); }else{// If not, simply clone objClone[key] = obj[key]; } } } } return objClone; } let a = [1, 2, 3, 4], b = deepClone (a); a[0]=2; console.log(a,b);Copy the code
2. Through the json object (undefined, the function, the symbol will be ignored in the process of conversion)
The object or value is first converted to a JSON string via json.stringify. Parse converts JSON strings into values or objects using json.parse.
console.log(JSON.stringify({ a: 1, b: 2,c:{ d:3} }));
const json = '{"a":1,"b":2,"c":{"d":3}}';
const obj = JSON.parse(json);
console.log(obj);
//{a: 1, b: 2, c: {d: 3} }
Copy the code
Faults: undefined cannot achieve object, function, deep copy of the symbol, displays is undefined
3. Extend by JQuery
$.extend() method: merges the contents of one or more objects into the target object.
$.extend( [deep ], target, object1 [, objectN ] )
Deep: Indicates whether to deeply merge objects.
Target: Indicates the target Object of the Object type.
Object: the merged object.
var newArray = $.extend(true,[],array);
4. Through the Object. The create ()
function deepClone(initalObj, finalObj) { var obj = finalObj || {}; for (var i in initalObj) { var prop = initalObj[i]; A = initalObj if(prop === obj) {continue; } if (typeof prop === 'object') { obj[i] = (prop.constructor === Array) ? [] : Object.create(prop); } else { obj[i] = prop; } } return obj; }Copy the code
Check each initalObj property, namely prop, and assign the value directly to obj if it is not a reference type. If so, check whether its constructor is Array. If so, it passes an empty Array.
5. Manually copy data
Assign a value from another object to the corresponding new object column.
var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = { a: obj1.a, b: obj1.b, c: obj1.c };
Write a deep copy yourself (recursively)
You should also consider undefined, the function, the symbol of the three.
Function deepClone(obj){if (obj instanceof Object! = true || obj == null){ var newObj = obj; }else{ var newObj = Array.isArray(obj)? [] : {} for {(key in obj) if (obj. HasOwnProperty (key)) {/ / here must put the function type, Date type and regular mentioned the if (obj [key] instanceof function | | obj[key] instanceof Date|| obj[key] instanceof RegExp){ newObj[key] = obj[key]; }else if(typeof obj[key] == 'object'){ newObj[key] = deepClone(obj[key]); }else{ newObj[key] = obj[key]; } } } } return newObj; } let a = 'abc'; Let b = [1, 2, 3, 4]. let c = { a : 1, b : 2, c : { d:3 }, e:function(){ }, f:undefined, g:Symbol } console.log(deepClone(a),deepClone(b),deepClone(c)); var test1 = deepClone(a); var test2 = deepClone(b); var test3 = deepClone(c); c.a = 2; c.c.d = 4; console.log(a,b,c); console.log(test1,test2,test3)Copy the code
Output: