Deep clone Shallow clone

Shallow clone: Primitive type is value pass, object type is reference pass. The reference value of the shallow-cloned object is the reference value of the copied object. The reference value of the two objects (such as an array or an embedded object) points to the same place.

Deep clone: The properties and values of all objects are copied, that is, the modification of all new objects does not affect the original objects.

There is an array of primitive types, objects, and re’s. Now clone the array.

 let arr1 = [10.20, {name: 'Little baby'}, /^\d+$/.function () {}]; 
Copy the code

Shallow clone

  1. Shallow clone: a clone of only the first level, and the second level and thereafter share the same heap address as the original object.
  2. More common methods:. (Expansion operator),slicewithObject.assign({}, obj)
  3. Function cloning through shallow cloning can be achieved, does not affect the original function. Because function cloning will create a separate space in memory, do not affect each other.
let arr2 = [...arr1];
console.log(arr1,arr2);
arr1 === arr2   //false
arr1[2] === arr2[2]   //true
Copy the code
let arr2 = arr1.slice(0);
Copy the code
function shallowCopy(target, origin){ 
    return Object.assign(target, origin); 
}
Copy the code

A deep clone

Common methods

1. JSON.parse(JSON.stringify())

  1. Based on the JSON method, the original object is converted into a string, and then the string is redefined as an object. At this time, the content of the deep clone is realized.
  2. Problem: If a value in an object is a re or a function, based onJSON.stringifyandJSON.parseFirst serialize the object toJSONString, and thenJSONA string deserialized to an object is no longer a re (becomes an empty object) or a function (becomes null).
  3. Only objects can be processed correctlyNumber,String,ArraySuch as can bejsonSo functions that cannot be represented by JSON will not be handled correctly.
let arr2 = JSON.parse(JSON.stringify(arr1));
arr1 === arr2       //false
arr1[2] === arr2[2]         //false
Copy the code

2. Write your own deep clone

  1. Ideas:

    1. Write out the framework of shallow cloning first, and then add conditional judgment on it.
    2. Next check whether the attribute is null, primitive type, function, re, date, and do the corresponding processing.
    3. Determine if the properties on the source object belong to the object, not the prototype, because we are just cloning the properties on the object.
    4. We then recursively call deep with that property as the source object.
    5. As a final step, remember to return the newObj object
  2. The main points of

    1. recursive
    2. Determine type
    3. Check loop (also called circular reference)
    4. You need to ignore the prototype
function deep(obj){

// Determine the type
    // Return null if null
    if (obj === null) return null;

    // If it is a basic data value or function, it can be returned directly (function does not need to clone)
    // typeof [] => 'object'
    // typeof {} => 'object'
    if (typeofobj ! = ='object') return obj;

    // If it is a re, clone the current re
    if (_type(obj) === '[object RegExp]') return new RegExp(obj); // Create a re
    // If the data is in date format
    if (_type(obj) === '[object Date]') return new Date(obj);

    // If it is an array or object
    // Create a new obj
                        
    // obj.constructor: Find the constructor of the owning class prototype, which points to the current class itself
    // => What type of value is guaranteed to be passed in, and the last one we created was newObj
    let newObj = new obj.constructor;
    for (let key in obj) {
        console.log(key)
        if (obj.hasOwnProperty(key)) { 
        //in determines whether the property is present in the current object and looks for it in the prototype
        //hasOwnProperty only determines whether the property is present in the current object

        // If the value of an item is a reference value, we need to further iterate through the loop and clone each item in the reference value => deep clonenewObj[key] = deep(obj[key]); }}return newObj;

}

function _type(value) { // Return the data type
    return Object.prototype.toString.call(value);
}
Copy the code

And then test it out

let arr1 = [10.20, {
    name: 'little red'
}, /^\d+$/.function () {console.log(123)}];

let arr2 = deepe(arr1);
console.log(arr2);
arr2[1] =30
arr2[2].name='test'
arr2[3] ='string'
console.log(arr1); // It's still the same
console.log(arr2);
Copy the code

Another example

let obj1 = {
			name: 'Ming'.ke: ['Chinese'.'mathematics'.'English'].color: {
				n: 'red'.m: 'blue'}};let obj2 = deep(obj1);
console.log(obj2);

obj2.ke.push('physical')
obj2.color['n'] ='yellow'
console.log(obj1); // Will not be affected, the original
console.log(obj2); 
Copy the code

Another way to write this is to loop in and then determine the type. Only object needs to be processed twice. The first one is to judge first and recycle.

function _type(value) {
        return Object.prototype.toString.call(value);
}

function _deepClone(obj) {	// OBJ must be array or object etc
    let newObj = new obj.constructor;
    for (let key in obj) {
        if(! obj.hasOwnProperty(key)) {let item = obj[key],
            itemType = _type(item);
            if(item ! = =null && typeof item === "object") { // Is not null and is not a basic type or function
                if (/(RegExp|Date)/.test(itemType)) { // just include one of the RegExp, Date types
                    newObj[key] = new item.constructor(item);
                    continue;
                 }
                // Only objects require deep cloning
                newObj[key] = _deepClone(item);
                continue; } newObj[key] = item; }}return newObj;
}
Copy the code