Deep copy and shallow copy in js

Posted by Bman900 on Mon, 14 Oct 2019 19:34:56 +0200

In the interview, we often ask about the deep and shallow copies of js, and often let us write by hand. Now let's understand the deep and shallow copies of JS thoroughly.

In js, when assigning a variable to another variable, the worth copy is actually a pointer. The pointer of two variables points to the same piece of push memory. When we change one value, the other value will also be affected.

So there are two cases, shallow copy and deep copy.

Shallow Copy: Reference to Copy Objects

// object
var obj1 = {
    a: 1,
    b: 2
};
var obj2 = obj1;

obj2.a = 3;

console.log(obj1); // {a: 3, b; 2}
console.log(obj2); // {a: 3, b: 2}

// array
var arr1 = [1, 2, 3];
var arr2 = arr1;

arr2.push(4);

console.log(arr1); // [1, 2, 3, 4]
console.log(arr2); // [1, 2, 3 ,4]

As you can see, a copy is a reference to an object. Common methods such as extend({}, obj) of jQuery or Array.prototype.slice() and Array.prototype.concat() all return a shallow copy of an array or object.

var arr1 = ['a', {a: 1}];
var arr2 = arr1.slice();

console.log(arr1 === arr2); // false

arr2[0] = 'b';
console.log(arr1); // ['a', {a: 1}] Basic types of values do not interact with each other

arr2[1].a = 2;
console.log(arr1); // ['a', {a: 2}] The value of the reference type can't be copied

To impress, we can manually implement a slice or jq extension ({}, obj)

function shallowClone(source) {
    if (!source || typeof source !== 'object') {
        throw new Error('error');
    }
    var resultObj = source.constructor === Array ? [] : {};
    for (var keys in source) {
        if (source.hasOwnProperty(keys)) {
            resultObj[keys] = source[keys];
        }
    }
    return resultObj;
}

var obj1 = {a: 1, b: [1, 2]}
var obj2 = shallowClone(obj1);

obj2.a = 2;
console.log(obj1); // {a: 1, b: [1, 2]}

obj2.b.push(3)
console.log(obj1); // {a: 1, b: [1, 2, 3]} 

Deep Copy: An Example of Copying Objects

Deep copy is to copy a new instance. The new instance does not affect the original instance. There are several ways to realize deep copy:

1. Use the third parameter of jq to recursively invoke $. extend(true, obj,...), or the implementation of third-party library functions such as lodash.

2. There are two ways to implement a deep copy, one is to copy it recursively, the other is JSON.parse and JSON.stringfy.

// Recursive implementation of deep copy
function deepClone(source) {
    if (!source || typeof source !== 'object') {
        throw new Error('error');
    }
    var resultObj = source.constructor === Array ? [] : {};
    for (var keys in source) {
        if (source.hasOwnProperty(keys)) {
            if (source[keys] && typeof source[keys] === 'object') {
                resultObj[keys] = source[keys].constructor === Array ? [] : {};
                resultObj[keys] = deepClone(source[keys]);
            }
            else {
                resultObj[keys] = source[keys];
            }
        }
    }
    return resultObj;
}

var a1 = {
    a: 1,
    b: [1, 2],
    c: {
        a: 1,
        b: 2
    }
};

var a2 = deepClone(a1);
a2.b.push(3)

console.log(a1); // {a: 1, b: [1, 2], c: {a: 1, b: 2}}
console.log(a2); // {a: 1, b: [1, 2, 3], c: {a: 1, b: 2}}

Topics: PHP JSON JQuery