The data type
Data is divided into basic data types and reference data types.
- Basic data types: String, Number, Boolean, Null, Undefined, Symbol. Basic data types are data stored directly on the stack.
- Reference data type: Array, Object. A reference data type stores that the object is referenced on the stack, and the real data is stored in memory.
To visualize this, let’s look at the following code:
// Let str1 = '123'; str2 = str1; str2 = '456'; console.log(str1); // '123' console.log(str2); // let arr1 = [1, 2, 3]; arr2 = arr1; arr2.push(4); console.log(arr1); // [1, 2, 3, 4] console.log(arr2); // [1, 2, 3, 4]Copy the code
As mentioned above, since the basic data type is stored directly, if we copy the basic data type and then modify the new data, the original data will not be affected.
When you copy a reference data type and modify the new data, it affects the original data.
Image examples:
- I have a big farm with houses, cars, sheep and prairie.
- Basic data type: I had one car before, and I bought another one so I have two cars, and the failure of one doesn’t affect the other. I had one house, and I built another, so I have two houses, and if one gets struck by lightning it doesn’t affect the other.
- In front of my house is a prairie, where some rotten grass was eaten by sheep. The sheep died of disease because of eating rotten grass. The prairie is still the prairie, but there is less grass inside; Sheep are still sheep, but there are fewer sheep inside.
In JavaScript, individual properties like house and car are called basic data types, which have their own private domains that you can clone, but the new one doesn’t affect the old one.
And if it’s a collective property like sheep or prairie, it’s object data, and if we store it one by one, it’s too much trouble to find it all at once, so the browser gives it a big field and tells you how to find it. So when you modify the content in it (sheep eat grass, less grass), it changes internally.
OK, now that we know about basic and reference data types, let’s explore assignment, shallow copy, and deep copy:
Assignment, deep copy, and shallow copy
/ * * *@name Assignment * /
const dataOne = {
title: "study".number: ["jsliang"."JavaScriptLiang"."LiangJunrong"]};const dataTwo = dataOne;
dataTwo.title = "play";
dataTwo.number = ["null"];
console.log(dataOne);
// dataOne: { title: 'play', number: ['null'] }
console.log(dataTwo);
// dataTwo: { title: 'play', number: ['null'] }
/ * * *@name Shallow copy * /
const dataThree = {
title: "study".number: ["jsliang"."JavaScriptLiang"."LiangJunrong"]};const dataFour = shallowClone(dataThree); // shallowClone to be implemented
dataFour.title = "play";
dataFour.number = ["null"];
console.log(datadataThreeOne);
// dataThree: { title: 'study', number: ['null'] }
console.log(dataFour);
// dataFour: { title: 'play', number: ['null'] }
/ * * *@name Deep copy * /
const dataFive = {
title: "study".number: ["jsliang"."JavaScriptLiang"."LiangJunrong"]};const dataSix = deepClone(dataFive); // deepClone to be implemented
dataSix.title = "play";
dataSix.number = ["null"];
console.log(dataFive);
// dataFive: { title: 'study', number: ['jsliang', 'JavaScriptLiang', 'LiangJunrong'] }
console.log(dataSix);
// dataSix: { title: 'play', number: ['null'] }
Copy the code
function shallowClone(source) {
var target = {};
for(var i in source) {
if (source.hasOwnProperty(i)) {
target[i] = source[i];
}
}
return target;
}
Copy the code
function clone(source) { var target = {}; for(var i in source) { if (source.hasOwnProperty(i)) { if (typeof source[i] === 'object') { target[i] = clone(source[i]); } else {target[I] = source[I]; } } } return target; }Copy the code
As above, we draw the conclusion:
-
Assignment: A copy of a reference address. Modification of assigned data, whether of a base or reference data type, affects the original data.
-
A shallow copy creates a new object with an exact copy of the original object’s property values. If the property is a primitive type, it copies the value of the primitive type, and if the property is a reference type, it copies the memory address, so if one object changes the address, it affects the other object.
-
A deep copy is a complete copy of an object from the heap, creating a new area of the heap to store the new object, and modifying the new object does not affect the original object.
In general, a shallow copy is a layer copy. In a shallow copy, changing the base data type does not affect the base data type of the original data, while changing the reference data type affects the original data type. However, the deep copy is an infinite level copy. In the deep copy, changing the base data type and reference data type does not affect the original data type.
Diagramming is shown below:
Shallow copy implementation
1.Object.assign()
The object.assign () method copies the enumerable properties of any number of source objects to the target Object and returns the target Object.
let obj1 = { person: {name: "kobe", age: 41},sports:'basketball' };
let obj2 = Object.assign({}, obj1);
obj2.person.name = "wade";
obj2.sports = 'football'
console.log(obj1); // { person: { name: 'wade', age: 41 }, sports: 'basketball' }
Copy the code
2. The _. Clone method of lodash
The library also provides _. Clone for Shallow Copy, which we’ll cover later.
var _ = require('lodash'); var obj1 = { a: 1, b: { f: { g: 1 } }, c: [1, 2, 3] }; var obj2 = _.clone(obj1); console.log(obj1.b.f === obj2.b.f); // trueCopy the code
3. Expand operator…
The expansion operator is an ES6 / ES2015 feature that provides a very convenient way to perform shallow copies, the same functionality as object.assign ().
let obj1 = { name: 'Kobe', address:{x:100,y:100}}
let obj2= {... obj1}
obj1.address.x = 200;
obj1.name = 'wade'
console.log('obj2',obj2) // obj2 { name: 'Kobe', address: { x: 200, y: 100 } }
Copy the code
4.Array.prototype.concat()
let arr = [1, 3, {
username: 'kobe'
}];
let arr2 = arr.concat();
arr2[2].username = 'wade';
console.log(arr); //[ 1, 3, { username: 'wade' } ]
Copy the code
5.Array.prototype.slice()
let arr = [1, 3, {
username: ' kobe'
}];
let arr3 = arr.slice();
arr3[2].username = 'wade'
console.log(arr); // [ 1, 3, { username: 'wade' } ]
Copy the code
Deep copy implementation
1.JSON.parse(JSON.stringify())
let arr = [1, 3, {
username: ' kobe'
}];
let arr4 = JSON.parse(JSON.stringify(arr));
arr4[2].username = 'duncan';
console.log(arr, arr4)
Copy the code
Json.stringify converts an object into a JSON string, and json.parse parses the string into an object. As it goes, new objects are created, and the object opens up a new stack for deep copy.
This method can do deep copies of arrays or objects, but it can’t handle functions and regees, because when these are processed based on json.stringify and json.parse, the resulting re is no longer a re (becomes an empty object) and the resulting function is no longer a function (becomes null).
Take the following example:
let arr = [1, 3, {
username: ' kobe'
},function(){}];
let arr4 = JSON.parse(JSON.stringify(arr));
arr4[2].username = 'duncan';
console.log(arr, arr4)
Copy the code
2. The _. CloneDeep method of the lodash library
The library also provides _. CloneDeep for Deep Copy
var _ = require('lodash'); var obj1 = { a: 1, b: { f: { g: 1 } }, c: [1, 2, 3] }; var obj2 = _.cloneDeep(obj1); console.log(obj1.b.f === obj2.b.f); // falseCopy the code
3. The jQuery. The extend () method
Jquery provides a $.extend for Deep Copy
$.extend(deepCopy, target, object1, [objectN])// Extend (deepCopy, target, object1, [objectN]Copy the code
var $ = require('jquery');
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
var obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f); // false
Copy the code
4. Handwritten recursive method
The recursive method implements the principle of deep cloning: iterating through objects and arrays until they contain all the basic data types, and then copying, which is called deep copy.
There is a special case needs to pay attention to is the condition of the circular reference object, the object’s properties directly refer to its own situation, solve the problem of circular reference, we can open up a extra storage space, to store the current objects and copy the object correspondence, when need to copy the current object, go to the storage space, find ever copy this object, Return if there is, continue to copy if there is not, so as to cleverly solve the problem of circular reference. If in doubt about this, please read carefully how ConardLi can write a deep copy to impress the interviewer. This article.
function deepClone(obj, hash = new WeakMap()) { if (obj === null) return obj; If (obj instanceof Date) return new Date(obj); if (obj instanceof Date) return new Date(obj); if (obj instanceof RegExp) return new RegExp(obj); If (typeof obj! == "object") return obj; If (hash. Get (obj)) return hash. Get (obj); let cloneObj = new obj.constructor(); Set (obj, cloneObj); // Constructor points to the current class's own hash.set(obj, cloneObj); For (let key in obj) {if (obj.hasOwnProperty(key)) {cloneObj[key] = deepClone(obj[key], hash); } } return cloneObj; } let obj = { name: 1, address: { x: 100 } }; obj.o = obj; // let d = deepClone(obj); obj.address.x = 200; console.log(d);Copy the code
Refer to the article
- Shallow copy and deep copy
- How to write a deep copy that will impress your interviewer?
- The ultimate quest for deep copy (unknown to 99% of people)