preface

Work will often encounter the operation of arrays, objects, you will certainly be the original array, objects’ backup ‘when the real operation of the backup also changed, at this time you have a face meng forced, then is why, is not already backed up, how to backup arrays, objects will also change. If you don’t understand how copying works, this article may help.

Javascript data types

Basic data types

String, number, null, undefined, Boolean, symbol(new in ES6) Variable values are stored in stack memory and can be accessed and modified directly. There is no copy of the basic data types. For example, you cannot change the value of 1

Reference types

Object Function RegExp Math Date is an Object stored in the heap memory where a variable holds a pointer to an address in the heap memory. When accessing a reference type, the object’s address pointer is fetched from the stack, and then the required data is fetched from the heap

Shallow copy

Why does the backup array object also change, in this case you are using a ‘backup’ which is actually a shallow copy

Simple copy of a reference

Var a = [1, 2, 3, 4]. var b = a; a[0] = 0; console.log(a,b);Copy the code



As you can see, array A is directly assigned to b, and a and B refer to an object address. Whenever the address value changes, the heap address pointed by the pointer to the stack memory of A and B will also change. This reference copy is only a new pointer to the variable stack memory, which is not significant

Concat, slice, and assign copies of objects

Same example

Var a = [1, 2, 3, 4]. var b = a.concat(); a[0] = 0; console.log(a,b);Copy the code



The array a[0] becomes 0, and the array B remains the same.

Array.prototype.slice and array.prototype. concat look like deep copies but are actually shallow copies

Var a = [1, 2, 3, 4] and {name:'ccy'}];
var b = a.concat();
a[3].name = 'hs';
console.log(a[3],b[3]);Copy the code

 

When Array A contains objects, array.prototype. slice and array.prototype. cancat copy the objects in the Array to share the same memory address, so they are essentially shallow copies

The same principle applies to object. assign (deep-copy objects whose attributes are primitive types).

var a = {age:18,name:'ccy',info:{address:'wuhan',interest:'playCards'}};
var b = Object.assign(a);
a.info.address = 'shenzhen';
console.log(a.info,b.info);Copy the code



So how do you make a deep copy of an object? Hold your glasses.

Write your own deep-copy function

var clone = function(obj){
        var construct = Object.prototype.toString.call(obj).slice(8,-1);
        var res;
        if(construct === 'Array'){
            res = [];
        }else if(construct === 'Object'){
            res = {}
        }
        for(var item in obj){
            if(typeof obj[item] === 'object'){
                res[item] = clone(obj[item]);
            }else{ res[item] = obj[item]; }}return res;
    };Copy the code

At first glance, it looks like it can handle the problem of an object’s property being an object. It can loop through until the property is a primitive type.

But if you think about it, an infinite loop can occur if the attributes of an object are referenced to each other. We can add another judgment that an object’s property breaks out of the current loop if it refers to an object pointer.

Deep copy

Deep copy is a perfect solution to the problem of shallow copy. It rewrites a block of address, and the basic type values of the properties from deep copy are the same.

Deep copy of JSON built-in objects

JSON objects are a new type introduced in ES5 (supported by IE8+). The JSON object parse method deserializes JSON strings into JS objects, and the Stringify method serializes JS objects into JSON strings. Deep copies of objects are also possible with both methods

var a = {age:1,name:'ccy',info:{address:'wuhan',interest:'playCards'}};
var b = JSON.parse(JSON.stringify(a));
a.info.address = 'shenzhen';
console.log(a.info,b.info);Copy the code



JSON can handle general objects for deep copy, but not functions, re, and so on

Custom deep-copy functions

We can optimize the custom copy function

var clone = function(obj){
        function getType(obj){
            return Object.prototype.toString.call(obj).slice(8,-1);
        }
        function getReg(a){
            var c = a.lastIndexOf('/');
            var reg = a.substring(1,c);
            var escMap = {'"': '\ \ "'.'\ \': '\ \ \ \'.'\b': '\\b'.'\f': '\\f'.'\n': '\\n'.'\r': '\\r'.'\t': '\\t'.'\w': '\\w'.'\s': '\\s'.'\d': '\\d'};
            for(var i in escMap){
                if(reg.indexOf(i)){
                    reg.replace(i,escMap[i]);
                }
            }
            var attr = a.substring(c+1);
            return new RegExp(reg, attr);
        }
        var construct = getType(obj);
        var res;
        if(construct === 'Array'){
            res = [];
        }else if(construct === 'Object'){
            res = {}
        }
        for(var item in obj){
            if(obj[item] === obj) continue; // If there is a reference, the current loop is brokenif(getType(obj[item]) === 'Function'){
                res[item] = new Function("return "+obj[item].toString())();
            }else if(getType(obj[item]) === 'RegExp'){
                res[item] = getReg(obj[item].toString());
            }else if(getType(obj[item]) === 'Object'){
                res[item] = clone(obj[item]);
            }else{ res[item] = obj[item]; }}return res;
    };Copy the code



Basic functions can be realized, re object deep copy, in the local only did a simple test, if there are problems, please timely comment pointed out.

CloneDeep (loDash) and $.extend (JQuery) are all deep copies.

The resources

Developer.mozilla.org/zh-CN/searc…

Github.com/wengjq/Blog…