This is the third day of my participation in the August More Text Challenge

Shallow copy

When you simply assign an array or object to another variable, you are actually making a shallow copy. Shallow copy is copying references, but the copied references point to the same object instance, and the operations affect each other.

1. Use “for in” to traverse

Simply copy the properties of an object. If the properties are of an underlying type, there is no problem, but if the object is of an object type (array, function), it is just copying the reference. Change the original properties, and the copied properties will also change

 function shallowCopy(source){
    var target=source instanceof Array ? [] : {};
    for(var i in source){
   // Use the hasOwnProperty method to determine whether the property exists
        if(source.hasOwnProperty(i)){ target[i]=source[i]; }}return target;
}

/ / test
var obj={
  a:1.b: [1.2.3].c:function(){
      console.log('i am c')}}var tar=shallowCopy(obj)
tar.c()         // "i am c"
obj.a=5
obj.a           / / 5
tar.a           / / 1
obj.b[0] =10
obj.b           / / [10, 2, 3]
tar.b           / / [10, 2, 3]

var arr=[1.2[4.5.6]]
var newArr=shallowCopy(arr)
newArr          / / [1, 2, 4 and 6]]
arr[0] =10
arr             / / [10, 2, and 4 and 6]]
newArr          / / [1, 2, 4 and 6]]
arr[2] [0] =10
arr             / / [1, 2, 10 and 6 []]
newArr          / / [1, 2, 10 and 6 []]

Copy the code

2.0bject . assign

Object.assign() copies property values. If the attribute value of the source object is a reference to an object, then it only refers to that reference. That is, if the attribute value of the Object is a simple type (e.g. String, number), assign({},srcObj); The resulting new object is a deep copy; If the attribute value is an object or some other reference type, it is actually shallow-copied for that object.

var obj={a:1.b: [1.2.3].c:function(){console.log('i am c')}}
var tar={};
Object.assign(tar,obj);
/ / test
obj.b[2] =1
console.log(obj.b)//[1, 2, 1]
console.log(tar.b)//[1, 2, 1]

Copy the code

3. Array method to achieve a shallow copy of the array

  • Array.prototype.slice
var arr=[1.2[3.4]].var newArr=arr.slice(0);

Copy the code
  • Array.prototype.concat
var arr=[1.2[3.4]].var newArr=arr.concat();

Copy the code
  • Array.from
var arr=[1.2[3.4]].var newArr= Array.from(arr);
console.log(newArr)//[1, 2, [3, 4]]

Copy the code

Deep copy

Reallocate memory in the heap, and create a new copy of all the attributes of the source object, and the copied object is completely isolated from the original object, without affecting each other.

1. Object serialization and deserialization

let obj = { name: 'aaa'.age: 30.action: function () {}}console.log(JSON.stringify(obj))  // Convert to json string
let str = '{"name":"aaa","age":30}'
let obj2 = JSON.parse(JSON.stringify(obj)) // Convert a JSON string to a JSON object
obj2.name = "bbb";
console.log(obj, obj2)

Copy the code

Existing pit

  • You can’t copy an object if it has functions and methods in it
  • Object constructor is discarded and all constructors point to Object
  • Object has a circular reference and an error is reported
// constructor
function person(pname) {
  this.name = pname;
}

const Messi = new person('Messi');

/ / function
function say() {
  console.log('hi');
};

const oldObj = {
  a: say,
  b: new Array(1),
  c: new RegExp('ab+c'.'i'),
  d: Messi
};

const newObj = JSON.parse(JSON.stringify(oldObj));

// The function cannot be copied
console.log(newObj.a, oldObj.a); // undefined [Function: say]
// Sparse array copy error
console.log(newObj.b[0], oldObj.b[0]); // null undefined
// Cannot copy the re object
console.log(newObj.c, oldObj.c); // {} /ab+c/i
// The constructor points to an error
console.log(newObj.d.constructor, oldObj.d.constructor); // [Function: Object] [Function: person]

// Object circular references will report an error
const oldObj = {};

oldObj.a = oldObj;

const newObj = JSON.parse(JSON.stringify(oldObj));
console.log(newObj.a, oldObj.a); // TypeError: Converting circular structure to JSON



Copy the code

Use recursion to complete deep copy

Do you need to recursively determine what data types the attributes of the object are, copy one by one

Ideas: The typeof operator returns “function” when it operates on a function, so the first if in the loop determines that that is false, so else branch. In tar[I] = obj[I], the function is assigned by reference, and if creating the same function is not an option, It just doesn’t fit the idea. Functions take up heap memory, which is best if shared.

function deep(dest, ori) { //dest target object ori source object
    for (var i in ori) {
        if (typeof ori[i] === 'object') {
            // Determine whether it is an array or an object
            dest[i] = (ori[i].constructor === Array)? [] : {};// Initialize the property
            deep(dest[i], ori[i])
        } else {
            dest[i] = ori[i];  // Non-reference attributes}}return dest;
}
/ / test
function simple(obj) {
    var o = {};
    Object.assign(o, obj);   // Target object Source object
    return o;
}
// var a = simple(Animal);
// var b = simple(Animal);
var a = deep({}, Animal)
var b = deep({}, Animal)
a.name = "tom";
a.skin.push("white");
// a.say();
// b.say();
console.log(a, b)

Copy the code

But in the following case, it will be called in a loop, it will get stuck in a recursive loop, which will cause the stack to burst, and you just need to determine whether an object’s field refers to that object or any parent of that object

var obj1 = {
    x: 1.y: 2
};
obj1.z = obj1;

var obj2 = deepCopy(obj1);

Copy the code

To solve

function deepCopy(obj, parent = null) {
    // Create a new object
    let result = {};
    let keys = Object.keys(obj),
        key = null,
        temp= null,
        _parent = parent;
    // If the field has a parent, you need to trace the parent of the field
    while (_parent) {
        // The field is a circular reference if it references its parent
        if (_parent.originalParent === obj) {
            // A circular reference returns a new object at the same level
            return _parent.currentParent;
        }
        _parent = _parent.parent;
    }
    for (let i = 0; i < keys.length; i++) {
        key = keys[i];
        temp= obj[key];
        // If the value of the field is also an object
        if (temp && typeof temp=== 'object') {
            // Recursively perform deep copy to pass the same class of objects to be copied and the new object to parent for easy traceability of circular references
            result[key] = DeepCopy(temp, {
                originalParent: obj,
                currentParent: result,
                parent: parent
            });

        } else{ result[key] = temp; }}return result;
}

var obj1 = {
    x: 1.y: 2
};
obj1.z = obj1;

var obj2 = deepCopy(obj1);
console.log(obj1); // It's too long
console.log(obj2); // It's too long


Copy the code