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…