Shallow copy and deep copy
preface
In JavaScript, we divide data into primitive data types (raw values) and reference types
- Values of primitive data types are accessed by value, and values of primitive types are immutable
- The values of reference types are accessed by reference, and the values of reference types are dynamically variable
var zxx = 100;
var zxx1 = 100;
console.log(zxx === zxx1) // true
var zxx2 = {a: 1, b: 2};
var zxx3 = {a: 1, b: 2};
console.log(zxx2 === zxx3) // falseTwo different objectsCopy the code
- Comparisons of basic data types are worth comparing
- A comparison of reference types is a comparison of reference addresses
In view of the characteristics of the above data types, we can initially think: the so-called shallow copy and deep copy may be copies of values and references (basic data types are copies of values, no distinction is made). In general, the copy objects we are dealing with are also for reference types.
- Shallow copy is a copy of a layer, deep object level copy reference; Deep copy is the copying of multiple layers, each level of data is copied;
- Both the shallow copy and the deep copy are for reference data types only. The shallow copy copies Pointers to an object, not the object itself. The old and new objects still share the same memory. However, a deep copy will create another identical object. The new object does not share memory with the original object, and modification of the new object will not change the original object.
- Difference: The shallow copy copies only the attributes of the first layer of the object, while the deep copy copies the attributes of the object recursively.
Problems with not using copies
var zxxArr = ["One"."Two"."Three"]
var zxxArrs = zxxArr
zxxArrs[1] = "love"; Console. log(zxxArr) // ["One"."love"."Three"]
console.log(zxxArrs) // ["One"."love"."Three"]Copy the code
Shallow copy:
Copy an object at a shallow level, copying only one layer of the object’s properties, not including the reference type data in the object.
Shallow copy of array:
Solution 1: Array slice method
var zxxArr = ["One"."Two"."Three"]
var zxxArrs = zxxArr.slice(0)
zxxArrs[1] = "love";
console.log(zxxArr) // ["One"."Two"."Three"]
console.log(zxxArrs) // ["One"."love"."Three"]Copy the code
Solution 2: Array concat method
var zxxArr = ["One"."Two"."Three"]
var zxxArrs = zxxArr.concat()
zxxArrs[1] = "love";
console.log(zxxArr) // ["One"."Two"."Three"]
console.log(zxxArrs) // ["One"."love"."Three"]Copy the code
Solution 3: ES6 extension operators…
var zxxArr = ["One"."Two"."Three"]
var zxxArrs = [...zxxArr]
zxxArrs[1] = "love";
console.log(zxxArr) // ["One"."Two"."Three"]
console.log(zxxArrs) // ["One"."love"."Three"]Copy the code
Shallow copy of object:
The first way
// Copy only the shallow copy of the first layerfunction simpleCopy (obj1) {
var obj2 = Array.isArray(obj1) ? [] : {}
for (let i in obj1) {
obj2[i] = obj1[i]
}
return obj2
}
var zxxObj = {
age: 18,
nature: ['smart'.'good'],
names: {
name1: 'zxx',
name2: 'xka'
},
love: function () {
console.log('zxx is a great girl')
}
}
var newZxxObj = simpleCopy(zxxObj)
newZxxObj.age = 8
newZxxObj.nature.push('why')
newZxxObj.names.name1 = 'why zxx'
newZxxObj.love = function () {
console.log('zxx is 18 years old'} console.log(zxxobj.age) // 18 Basic data types do not change console.log(zxxobj.nature) // ["smart"."good"."why"] reference types change console.log(zxxObj['names']) // {name1: "why zxx", name2: "xka"} The reference type will change console.log(zxxObj['love']) // ƒ () {console.log('zxx is a great girl')}Copy the code
Second method: object. assign (can only handle objects with one layer of depth)
var zxxObj = {
age: 18,
nature: ['smart'.'good'],
names: {
name1: 'zxx',
name2: 'xka'
},
love: function () {
console.log('zxx is a great girl')
}
}
var newZxxObj = Object.assign({}, zxxObj);
newZxxObj.age = 8
newZxxObj.nature.push('why')
newZxxObj.names.name1 = 'why zxx'
newZxxObj.love = function () {
console.log('zxx is 18 years old')
}
console.log(zxxObj.age) // 18
console.log(zxxObj.nature) // ["smart"."good"."why"]
console.log(zxxObj['names']) // {name1: "why zxx", name2: "xka"}
console.log(zxxObj['love']) // ƒ () {console.log('zxx is a great girl')}Copy the code
Var newZxxObj = {… zxxObj}
var zxxObj = {
age: 18,
nature: ['smart'.'good'],
names: {
name1: 'zxx',
name2: 'xka'
},
love: function () {
console.log('zxx is a great girl') } } var newZxxObj = {... zxxObj} newZxxObj.age = 8 newZxxObj.nature.push('why')
newZxxObj.names.name1 = 'why zxx'
newZxxObj.love = function () {
console.log('zxx is 18 years old')
}
console.log(zxxObj.age) // 18
console.log(zxxObj.nature) // ["smart"."good"."why"]
console.log(zxxObj['names']) // {name1: "why zxx", name2: "xka"}
console.log(zxxObj['love']) // ƒ () {console.log('zxx is a great girl')}Copy the code
Complete sample
var person = {
name: 'tt',
age: 18,
friends: ['oo'.'cc'.'yy']}function shallowCopy(source) {
if (!source || typeof source! = ='object') {
throw new Error('error');
}
var targetObj = source.constructor === Array ? [] : {};
for (var keys in source) {
if (source.hasOwnProperty(keys)) {
targetObj[keys] = source[keys]; }}return targetObj;
}
var p1 = shallowCopy(person);
console.log(p1)Copy the code
In the code above, we created one
shallowCopy
Function, which takes an argument that is the object to be copied.
- First you create an object
- then
for... in
To avoid looping over properties that would be iterated over the prototype, use thehasOwnProperty
The restriction loop adds each property and value of the copied object to the created object only on the object itself - Finally, this object is returned
By testing, we get p1, which is almost identical to the Person object. What’s the difference between this result and an assignment like person?
var p2 = person; Person.name = person.name ='tadpole';
person.age = 19;
person.friends.push('tt')
p2.name // tadpole
p2.age // 19
p2.friends // ["oo"."cc"."yy"."tt"]
p1.name // tt
p1.age // 18
p1.friends // ["oo"."cc"."yy"."tt"]Copy the code
Above we created a new variable
p2
That will be
person
Assigned to
p2
And then compare the two variables
Deep copy:
Shallow copy Because it copies only the properties of one layer of objects, when there are child objects, the child objects will affect each other. So, a deep copy is a copy of an object and all its children
Method one:
Json.stringify converts the object into a string, and json.parse converts the string into a new object.
undefined
2, will ignore symbol
Cannot serialize function, cannot copy function
Const a = {val:2}; a.target = a; Copying A will result in stack overflow because of infinite recursion
5. Failed to handle RegExp, Date, Set, Map, etc
Cannot handle regex
7. Discard object constructor. After deep copy, whatever the original constructor of this Object was, after deep copy, it will become Object.
var zxxObj = {
age: 18,
why: undefined,
why1: Symbol('why1'),
nature: ['smart'.'good'],
names: {
name1: 'zxx',
name2: 'xka'
},
love: function () {
console.log('zxx is a great girl')
}
}
var newZxxObj = JSON.parse(JSON.stringify(zxxObj))
newZxxObj.age = 8
newZxxObj.nature.push('why')
newZxxObj.names.name1 = 'why zxx'
newZxxObj.love = function () {
console.log('zxx is 18 years old')
}
console.log(zxxObj.age) // 18
console.log(zxxObj.nature) // ["smart"."good"]
console.log(zxxObj['names']) // {name1: "zxx", name2: "xka"}
console.log(zxxObj['love']) // ƒ () {console.log('zxx is a great girl')}
console.log(newZxxObj['love']) // undefined functionThere's no way to convert it to JSON. console.log(newZxxObj) // {age: 8, nature: Array(3), names: Object, love:function} why why1 love will be ignoredCopy the code
In circular reference cases, an error is reported.
let obj = {
a: 1,
b: {
c: 2,
d: 3
}
}
obj.a = obj.b;
obj.b.c = obj.a;
let b = JSON.parse(JSON.stringify(obj));
// Uncaught TypeError: Converting circular structure to JSONCopy the code
Method two: cyclic recursion
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i ininitalObj) { var prop = initalObj[i]; // Avoid endless loops caused by cross-referencing objectsif(prop === obj) {
continue;
}
if (typeof prop === 'object') {
obj[i] = (prop.constructor === Array) ? [] : {};
arguments.callee(prop, obj[i]);
} else{ obj[i] = prop; }}return obj;
}
var zxxObj = {
age: 18,
nature: ['smart'.'good'],
names: {
name1: 'zxx',
name2: 'xka'
},
love: function () {
console.log('zxx is a great girl')
}
}
var newZxxObj = deepClone(zxxObj);
newZxxObj.age = 8
newZxxObj.names.name1 = 'newzxx'
console.log(zxxObj)
console.log(newZxxObj)Copy the code
The output
The $.extend method in jquery and Zepto can be used as a deep copy
var $ = require('jquery');
var newObj = $.extend(true, {}, obj);Copy the code
Example:
function deepCopy(source) {if(!source || typeof source! = ='object'){
throw new Error('error');
}
var targetObj = source.constructor === Array ? [] : {};
for(var keys in source) {if(source.hasOwnProperty(keys)){
if(source[keys] && typeof source[keys] === 'object'){
targetObj[keys] = source[keys].constructor === Array ? [] : {};
targetObj[keys] = deepCopy(source[keys]);
}else{
targetObj[keys] = source[keys]; }}}return targetObj;
}
var obj1 = {
arr: [1, 2, 3],
key: {
id: 22
},
func: function() {
console.log(123)
}
}
var obj2 = deepCopy(obj1);
obj1.arr.push(4);
obj1.arr // [1, 2, 3, 4]
obj2.arr // [1, 2, 3]
obj1.key === obj2.key // false
obj1.func === obj2.func // trueCopy the code
For deep-copied objects, changing the source object has no effect on the resulting object. It’s just that the methods of the source object are lost in the copying process because of serialization
JavaScript
Object, all functions and prototype members are intentionally ignored.