preface
There are different ways to copy objects in javascript: shallow copy and deep copy, and if you’re not familiar with the language, copying objects can easily fall into the trap. To answer this question you need to understand javascript data types and the difference between heap and stack.
After reading this article, I hope you understand:
1. What is the difference between base types and reference types, and between stacks and stacks?
What are deep/shallow copies, and how are they different from assignment?
3, what are the implementation methods of deep/shallow copy, and what are the limitations?
Javascript data types
Basic types: String, Number, Boolean, Null, Undefined
Reference types: Object contains function, Array, Date, etc.
Heap and stack
-
Stack: The stack will automatically allocate memory space, will automatically free, to store basic types, simple data segments, occupy a fixed amount of space. (Basic types: String, Number, Boolean, Null, Undefined)
-
Heap: dynamically allocated memory, not automatically released or of any size, for reference types, objects that may be composed of multiple values, stored in heap memory, containing variables of reference types, which actually hold Pointers to the object rather than the variable itself. (Reference types: Function, Array, Object, Date, etc.)
The difference between
Stack: All variables defined in a method are stored in stack memory, and the method’s stack is destroyed when the method completes execution.
- Advantages: Faster access than the heap, only second to the register directly located in the CPU, data can be shared;
- Disadvantages: The size and lifetime of data in the stack must be determined, inflexible.
Heap: An object in heap memory is not destroyed at the end of a method, and even after the method ends, the object may be referenced by another reference variable (parameter passing). The object is created for reuse and will be saved to the runtime data area.
What is deep/shallow copy? Assignment vs deep/shallow copy
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. In short, the basic data types of objects before and after copying do not affect each other. However, the reference types of objects before and after copying do affect each other because they share the same memory block.
A deep copy is a complete copy of an object from the memory, creating a new area in the heap memory to store the new object, and a recursive copy of the child objects (reference type data) in the object. The two objects before and after the copy do not affect each other.
In short, shallow copies only Pointers to an object, not the object itself, and the old and new objects share the same block of memory. But deep copy will create another identical object, the new object and the original object do not share memory, modify the new object will not change to the original object.
The assignment
When we assign an object to a new variable, we assign the object’s address on the stack, not the data in the heap. That is, two objects point to the same storage space. If any object is changed, it is the content of the changed storage space. Therefore, the two objects are linked.
Shallow copy implementation
The object.assign () method copies the enumerable attributes of any source Object to the target Object and returns the target Object.
_. Clone method of lodash
3. Expand operator…
4, Array. The prototype. The concat ()
5, Array. The prototype. The slice ()
Deep copy implementation
1, the JSON. Parse (JSON. Stringify ())
Json.stringify converts the object into a JSON string, and json.parse parses the string into an object. As you go, new objects are created, and the object opens up a new stack for deep copy. Although this approach can implement deep copies of arrays or objects, it cannot deal with functions and regex, object circular references and other problems
2. CloneDeep method for lodash
Extend ()
$. Extend (deepCopy, target, object1, [objectN]); 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); // falseCopy the code
4, handwritten recursive copy recursive method to achieve the principle of deep cloning: traverse the object, array until the inside is the basic data type, and then to copy, is 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(origin, hash = new WeakMap(a)) {
if (origin === null) return origin; // If it is null or undefined, I will not copy it
if (origin instanceof Date) return new Date(origin);
if (origin instanceof RegExp) return new RegExp(origin);
// May be objects or ordinary values if functions do not need deep copies
if (typeoforigin ! = ="object") return origin;
// If it is an object, make a deep copy and check for circular references
if (hash.get(origin)) return hash.get(origin);
let target = new origin.constructor();
// Find the constructor from the parent class stereotype, which points to the current class itself
hash.set(origin, target);
for (let key in origin) {
if (origin.hasOwnProperty(key)) {
// Implement a recursive copytarget[key] = deepClone(origin[key], hash); }}return target;
}
Copy the code
let obj = { name: 1.address: { x: 100}}; obj.o = obj;// The object has a circular reference
let d = deepClone(obj);
obj.address.x = 200;
console.log(d);
Copy the code