preface
JS data types are mainly divided into two types: basic data type and reference data type.
The basic type of data is stored directly in stack memory; Data of reference type is stored in heap memory, and the memory address (pointer) of this data is stored in stack memory.
let a = 'first'; let arr1 = [1, 2, '3']; let obj = { a: 'second', b: 16, c: a, d: arr1}; a = 'first1'; console.log(obj) // { a: 'second', b: 16, c: 'first', d: [1, 2, "3"]} arr1.push('44'); Console. log(obj) console.log(obj) {a: 'second', b: 16, c: 'first', d: [1, 2, "3", "44"]} // change obj.dobj.d.ush (55) // change arr1 console.log(arr1); // [1, 2, "3", "44", 55]Copy the code
When you change the value of a reference type, any variable that references that value also changes.
Looking at the example above, you can see that if our variable points to the same memory address, changing its value will affect all variables that refer to it. To solve the above problem, we need to make shallow or deep clone copies of the values.
What is theShallow copyandDeep copy
Shallow and deep copies are mainly for objects (including functions, Regex, and Date) and arrays.
Shallow copy only copies the memory address (pointer) that points to an object, not the object itself. The old and new objects share one memory address, and modification of either one affects the other. A shallow copy creates a new object and copies the properties of the original object one by one. If the property of the original object is the base type, the copy is the value of the property; If the property of the original object is a reference type, the copy is the memory address, so the modification will affect each other.
Deep copy creates an additional identical object, the old and new objects do not share the same memory address, and changes do not affect each other.
Shallow copy implementation
Shallow copy implements only one layer of copy, not deep copy
Object shallow copy
1. Expand operators
let obj = { a: '', b: null, c: undefined, d: ['1', 2, 3, { a: 12 }], }; let shallowCloneObj = {... obj}; console.log(shallowCloneObj)Copy the code
2. Object.assign()
let obj = {
a: '',
b: null,
c: undefined,
d: ['1', 2, 3, { a: 12 }],
};
let shallowCloneObj = Object.assign(obj);
console.log(shallowCloneObj)
Copy the code
3. for.. The in traverse
function shallowClone(obj) { if (! isObject(obj)) return obj; const cloneObj = Array.isArray(obj) ? [] : {}; for (let prop in obj) { if (obj.hasOwnProperty(prop)) { cloneObj[prop] = obj[prop]; } } return cloneObj; };Copy the code
4. Assign values in sequence
let obj = {
a: '',
d: ['1', 2, 3, { a: 12 }],
};
let shallowCloneObj = {};
shallowCloneObj.a = obj.a
shallowCloneObj.d = obj.d
Copy the code
Array shallow copy
Array.prototype methods that return a new Array can be considered shallow copies
1. Array.prototype.slice()
let arr = [1, 2, 3, 4];
console.log(arr.slice(0))
Copy the code
2. Array.prototype.concat()
let arr = [1, 2, 3, 4];
console.log(arr.concat([]))
Copy the code
3. Array.prototype.map()
let arr = [1, 2, 3, 4];
console.log(arr.map((ele) => ele))
Copy the code
3. Array.prototype.filter()
let arr = [1, 2, 3, 4];
console.log(arr.filter(() => true))
Copy the code
4. Expand operators
let arr = [1, 2, 3, 4];
console.log([...arr])
Copy the code
5. Assign values in sequence
Can be used when the value is simple
let arr = [1, 2];
let shallowCloneArr = [arr[0], arr[1]]
Copy the code
Handwriting to achieve shallow copy
Const isObject = (obj) => typeof obj === 'object' &&obj! == null; const shallowClone = (obj) => { if (! isObject(obj)) return obj; const cloneObj = Array.isArray(obj) ? [] : {}; for (let prop in obj) { if (obj.hasOwnProperty(prop)) { cloneObj[prop] = obj[prop]; } } return cloneObj; }Copy the code
Deep copy implementation
JSON.stringfy()
Json.stringfy () is a common deep-copy method on the front end. It serializes an object into a JSON string, converts the contents of the object into a string, and then uses json.parse () to generate a new object from the JSON string.
let obj = { a: '', b: null, c: undefined, // undefined d: ['1', 2, 3, { a: 12 }], e: {m: 5, n: '66'}, m: New Date(), // Date n: NaN, f: function fn(){console.log('11')}, // function r: new RegExp(' d'), // RegExp s: Symbol(66), // Symbol [Symbol('test')]: 1,} // Define the unenumerable attribute object.defineProperty (obj, 'innumerable', {enumerable: false, value: 'innumerable'}); console.log(JSON.parse(JSON.stringify(obj))); / * * the results are as follows: a "b" : null d: (4) [" 1 ", 2, 3, {...}] e: {5, m: n: "66"} m: "the 2021-09-09 T11:42:05. 771 z, n: null r: {} * * /Copy the code
But there’s a catch:
- The value of the copied object, if anyfunction,
undefined
,Symbol
These types, afterJSON.stringify
The key/value pair disappears in the serialized string - If it is
RegExp
Object, will become{}
- If it is
Date
Will be converted to a string NaN
Will be converted tonull
- Non-enumerable properties (
enumerable: false
), cannot be copied
lodash.cloneDeep()
Source:
lodash.cloneDeep()
Handwritten recursive implementation
Function cloneDeep(target) {// If (! typeof targe === 'object') { return target; } // define an empty object let newObj = array.isarray (target)? [] : {}; for(let key in target) { newObj[key] = typeof target[key] === 'object' ? cloneDeep(target[key]) : target[key] } return newObj; }Copy the code
thinking
The difference between assignment and shallow copy
- If it’s a basic type, you can say that assignment is the same as shallow copy,
- In the case of reference type data, assignment assigns the address of the object in the stack, not the data in the heap. The two data affect each other. If one changes, the other changes. A shallow copy creates a new object and copies the properties of the original object one by one. If the property of the original object is the base type, the copy is the value of the property; If the attribute of the original object is a reference type
conclusion
If this article helped you, please like 👍 and follow ⭐️.
If there are any errors in this article, please correct them in the comments section 🙏🙏.