preface
Why write copy this article? A colleague mentioned copying the other day and said assignment is a shallow copy. Another colleague said assignment is not the same as shallow copy. I have some doubt, so I went to the MDN search copy related content, found no copy about the essence of the concept, there is no way to only through the practice, at the same time to see some predecessors article summarizes this article about copy of the content, this article also belong to the public, “programmers growth refers to the north” learning route “JS will know will be” content.
Koala is dedicated to sharing the complete Node.js technology stack, from JavaScript to Node.js, to back-end database. Wish you become an excellent senior Node.js engineer. [Programmer growth refers to north] Author, Github blog open source project github.com/koala-codin…
The relationship between data types and stacks
Base and reference types
-
Basic types: undefined, null, Boolean, String, Number, Symbol
-
Reference types: Object, Array, the Date, the Function, the RegExp, etc
storage
- Basic type: Values of the basic type occupy a fixed size in memory and are stored in
Stack memory
In (not includedclosure
In)
- Reference type: The value of a reference type is an object, stored in
Heap memory
In the. The stack memory stores the variable identifier of the object and the storage address of the object in the heap memory (reference). The reference data type stores a pointer in the stack to the starting address of the entity in the heap. When the interpreter looks for a reference value, it first retrieves its address in the stack and then retrieves the entity from the heap.
Note:
closure
Variables in are not stored in stack memory, but in heap memory. That’s kind of nice, ifclosure
The variable is saved inStack memory
As the function in the outer layer is destroyed from the call stack, the variables are definitely destroyed, but if stored in heap memory, the in-memory function can still access the variables in the destroyed function in the outer layer. Take a look at the corresponding code to understand:
function A() {
let a = 'koala'
function B() {
console.log(a)
}
return B
}
Copy the code
- The shallow and deep copies discussed in this article are for reference types, not for underlying types.
The assignment operation
Base data type replication
Look at a piece of code
let a ='koala';
let b = a;
b='Programmer growth is north';console.log(a); // koala
Copy the code
Basic data type replication diagram:
Conclusion: When the data in the stack memory changes, the system will automatically assign a new value to the new variable in the stack memory, and the two variables are independent of each other.
Reference data type replication
Look at a piece of code
let a = {x:'kaola'.y:'kaola1'}
let b = a;
b.x = 'Programmer growth is north';
console.log(a.x); // Programmer growth refers to north
Copy the code
Reference data type replication diagram:
conclusionA copy of the reference type, which also allocates a new value to the new variable B, is reported in the stack memory, but the specific value of this variable is not in the stack, the stack is only an address pointer. Both variable address Pointers are the same, pointing to objects in heap memory, so when B.x changes, A.x also changes.
Shallow copy
Shallow copy definition:
A function called array.prototype. slice can implement a shallow copy of the original Array. For the official conclusion, let’s verify it with two pieces of code and summarize the definition of shallow copy.
- First code:
var a = [ 1.3.5, { x: 1}];var b = Array.prototype.slice.call(a);
b[0] = 2;
console.log(a); // [ 1, 3, 5, { x: 1 } ];
console.log(b); // [ 2, 3, 5, { x: 1 } ];
Copy the code
As can be seen from the output result, after shallow copy, array A [0] does not change with the change of array B [0], indicating that a and B reference addresses in stack memory are not the same.
- Second code
var a = [ 1.3.5, { x: 1}];var b = Array.prototype.slice.call(a);
b[3].x = 2;
console.log(a); // [ 1, 3, 5, { x: 2 } ];
console.log(b); // [ 1, 3, 5, { x: 2 } ];
Copy the code
From the output, it can be seen that after the shallow copy, the properties of the objects in the array will change according to the modification, indicating that the object property reference of the existing object is copied during the shallow copy.
- Shallow copy definition
Analyze the shallow copy definition with this official Slice shallow copy function:
The new object copies the values and references of non-object attributes of the existing object. If the term is not understood in another way, a new object directly copies a reference to an existing object’s object properties, that is, a shallow copy.
Shallow-copy instance
Object.assign
- Grammar:
Syntax: Object.assign(target,… sources)
The method that copies objects in ES6 takes the first parameter as the target to be copied and the remaining parameters as the source object to be copied (which can be multiple).
- For example:
let target = {};
let source = {a:'koala'.b: {name:'Programmer growth is north'}};
Object.assign(target ,source);
console.log(target); // {a: 'koala', b: {name: 'koala'}}
source.a = 'smallKoala';
source.b.name = 'Programmer growth means north.'
console.log(source); // {a: 'smallKoala', b: {name: 'smallKoala'}}
console.log(target); // {a: 'koala', b: {name: 'koala'}}
Copy the code
Object.assign is a shallow copy. It creates a new Object in the root attribute (the first level of the Object), but copies the same memory address if the attribute value is an Object.
- Object.assign Precautions
- Copy only the source object’s own properties (no inherited properties)
- It does not copy the object’s non-enumerable properties
undefined
andnull
They can’t be turned into objects, they can’t beObject.assign
Parameter, but can be used as a source object
Object.assign(undefined) / / an error
Object.assign(null) / / an error
let obj = {a: 1};
Object.assign(obj, undefined) === obj // true
Object.assign(obj, null) === obj // true
Copy the code
- Properties,
Symbol
Value, which can be copied by Object.assign.
Array.prototype.slice
This function was analyzed when the shallow copy concept was defined, see above.
Array.prototype.concat
- grammar
var new_array = old_array.concat(value1[, value2[, …[, valueN]]])
Parameters: Concatenate arrays and/or values into new arrays
- For example
let array = [{a: 1}, {b: 2}];
let array1 = [{c: 3}, {d: 4}];
let array2=array.concat(array1);
array1[0].c=123;
console.log(array2);// [ { a: 1 }, { b: 2 }, { c: 123 }, { d: 4 } ]
console.log(array1);// [ { c: 123 }, { d: 4 } ]
Copy the code
Array.prototype.concat is also a shallow copy, just creating a new object in the root property (the first level of the object), but copying the same memory address if the property value is an object.
. Extended operator
- grammar
var cloneObj = { … obj };
- For example
let obj = {a:1.b: {c:1}}
letobj2 = {... obj}; obj.a=2;
console.log(obj); //{a:2,b:{c:1}}
console.log(obj2); //{a:1,b:{c:1}}
obj.b.c = 2;
console.log(obj); //{a:2,b:{c:2}}
console.log(obj2); //{a:1,b:{c:2}}
Copy the code
The extension operator is also a shallow copy. You cannot copy an attribute whose value is an object into two different objects, but it is also a convenience if the attribute is of primitive type.
Note: The above 4 shallow copy methods do not change the original array, only return a shallow copy of the original array elements of a new array.
Implement a shallow copy yourself
How it works: New objects copy the values and references of non-object attributes of existing objects, that is, object attributes are not copied to memory.
- Implementation code:
function cloneShallow(source) {
var target = {};
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; }}return target;
}
Copy the code
- HasOwnProperty = hasOwnProperty = hasOwnProperty = hasOwnProperty
for in
for… The IN statement iterates through an object’s own, inherited, enumerable, non-symbol properties in any order. For each different attribute, the statement is executed.
hasOwnProperty
Grammar: obj. HasOwnProperty (prop)
Prop is the name of the property string or Symbol to be tested
This function returns a Boolean value, and all objects that inherit from Object inherit to the hasOwnProperty method. Unlike the in operator, this function ignores properties inherited from the prototype chain as well as its own properties.
Deep copy operation
The assignment operation and the shallow copy operation, if you can already think of what is a deep copy, let’s go straight to the definition of deep copy.
Deep copy definition
Deep copy creates a new area of heap memory to store the new object. The new object does not share memory with the original object, and modification of the new object will not change to the original object.
Deep-copy instance
JSON.parse(JSON.stringify())
Json.stringify () is a common deep-copy method used in front-end development. The principle is to serialize an object into a JSON string, convert the contents of the object into a string and store it on disk, and then convert the JSON string into a new object using json.parse () deserialization
- For example:
let arr = [1.3, {
username: ' koala'
}];
let arr4 = JSON.parse(JSON.stringify(arr));
arr4[2].username = 'smallKoala';
console.log(arr4);// [ 1, 3, { username: 'smallKoala' } ]
console.log(arr);// [ 1, 3, { username: ' koala' } ]
Copy the code
The implementation of deep copy, when changing the value of the object in the array, the contents of the original array does not change. Json.stringify () can implement deep copy, but has some drawbacks such as not being able to handle functions.
- Json.stringify () implements deep copy notes
- If the value of the copied object has a function,undefined,symbol, the key-value pair will disappear in the JSON string serialized by json.stringify ()
- Cannot copy non-enumerable properties, cannot copy the prototype chain of an object
- Copying the Date reference type becomes a string
- Copying the RegExp reference type becomes an empty object
- Object containing NaN, Infinity, and -infinity becomes NULL
- Looping applications that cannot copy objects (i.e. obj[key] = obj)
Implement a simple deep copy yourself
Deep copy, the main idea is recursion, iterating through objects and arrays until they are all basic data types, and then copying, that is, deep copy. Implementation code:
// Define a function that detects data types
function isObject(obj) {
return typeof obj === 'object'&& obj ! =null;
}
function cloneDeep(source) {
if(! isObject(source))return source; // Non-objects return themselves
var target = Array.isArray(source) ? [] : {};
for(var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
if (isObject(source[key])) {
target[key] = cloneDeep(source[key]); // Notice here
} else{ target[key] = source[key]; }}}return target;
}
Copy the code
What this simple deep copy does not take into account is that when you encounter a circular reference, you get caught up in a circular recursive process that causes the stack to burst
// RangeError: Maximum call stack size exceeded
Copy the code
Do you have any good ideas? You can write codes and discuss them in the comments section.
Third-party deep copy libraries
CloneDeep is also available for Deep Copy (loDash is a good third party open source library, there are many good functions, you can also see the implementation of the source code).
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);
// false
Copy the code
Summary of Copy content
Sum it up with a picture
Today share so much, if you are interested in sharing the content, you can pay attention to the public account “programmer growth refers to north”, or join the technical exchange group, we discuss together.
Advanced technology route
Join us and learn!