I learned a lot from watching Axuebin’s 2020 interview review in Denver. So I decided to start writing some basic documentation to improve myself and review native JS.
Basic data types
Data types in javascript are divided into base data types and reference data types
Underlying data types
String, Number, Boolean, Null, Undefined, Symbol are stored in a single location in memory, so they can be accessed directly
Reference data type
Refers to objects stored in heap memory, so a value of a reference type holds a pointer to an object stored in the heap. In addition to the six basic data types above, all that remains are reference types, collectively called Object types. Subdivided, there are: Object, Array, Date, RegExp, Function, and so on. When we need to access the values of these three reference types, we first need to get the object’s address pointer from the stack, and then get the required data from the heap memory.
JS heap memory and stack memory
There are two main locations for storing variables in the JS engine, heap memory and stack memory.
Similar to Java memory, stack memory is used to store variables of various basic types, including Boolean, Number, String, Undefined, Null, **, and Pointers to object variables. In this case, stack memory feels like a linear array of space, with each small unit roughly equal in size.
Heap memory is mainly responsible for storing variable types such as Object, as shown in the figure below
Why are the underlying data types in the stack and the reference data types in the heap?
- The heap is larger than the stack, and the stack is faster than the stack.
- The underlying data types are stable and relatively memory intensive.
- The reference data type size is dynamic and infinite.
- Heap memory is unordered storage and can be retrieved directly by reference.
The assignment
The process of assigning a value or object to another variable
Basic data types
For basic data type replication, the system automatically allocates an address in memory for the new variable. After the assignment, the two variables do not affect each other.
var a = 'haha';
var b= a;
console.log(b) //haha
a = 'heihei'
console.log(a,b) //heihei haha
Copy the code
The reference data type system also automatically assigns a value in stack memory for the new variable, but this value is just an address. In other words, the copied variable and the original variable have the same address value, pointing to the same object in heap memory, so they affect each other!
var a = {
name: 'haha',
age: '23',
sex: 'boy'
}
var b = a
console.log(b)
a.name = 'heihei';
console.log(a)
console.log(b)
Copy the code
Shallow Copy
What is shallow copy?
Creates a new object with an exact copy of the original object property values. If the original data is of a primitive type, it copies the value of the primitive type. If the original data is of a reference type, it copies the memory address of the original data, so if one object changes the address, it affects the other object.
In the figure above, the SourceObject is the original object, which contains the base type attribute field1 and the reference type attribute refObj. After a shallow copy, the field2 and filed1 properties are different and do not affect each other. But the reference type refObj is still the same, and changing it will affect another object.
A shallow copy only solves the problem of the first layer, copying the first base type value and the reference type address of the first layer.
Shallow copy of the object
Object.assign
The enumerable attribute () method is used to assign all enumerable attribute values from one or more source objects to the target object, and then return the target object.
var a = { name: 'haha', age: '23', sex: 'boy', option: { address: }} var b = object. assign({},a) a.name = 'heihei'; Address = 'Taiyuan, Shanxi' console.log(a) console.log(b)Copy the code
When the name attribute of A is modified, B does not change, because the name attribute value of A is a basic data type. After the replication, the two variables have complementary effects. When the address attribute of A is modified, both the address attribute of A and B are changed, because the attribute value of option is a reference data type, which points to the same address after the replication. So when one changes, the other changes.
If the object’s attribute value is a simple type (string, number…) Object.assign ({}, srcObj) is used to make a deep copy of the new Object. If the attribute value is an Object or other reference type, then the Object is a shallow copy.
Using extension operators… (spread)
Var a = {name: 'haha', age: '23', sex: 'boy', option: {address: 'Xi 'an'}} var b = {... a} a.name = 'heihei'; Address = 'Taiyuan, Shanxi' console.log(a) console.log(b)Copy the code
You can see that the effect is the same as using object.assign ().
A shallow copy of the array
array.slice(start, end)
Start: optional. Specify where to start. If it is negative, it specifies the position from the end of the array. That is, -1 is the last element, -2 is the next-to-last element, and so on.
End: optional. Specify where to end the selection. This parameter is the array subscript at the end of the array fragment. If this parameter is not specified, the shard array contains all elements from start to the end of the array. If this parameter is negative, it specifies the element from the end of the array.
Let a = [0, '1', [2,3]] let b = a.ice (1); // Select console.log(b) a[1] = '66' a[2][1] = '666' console.log(a) console.log(b)Copy the code
It can be seen that the value of B [0] does not change after a[1] is changed, but the corresponding value of B [1][0] also changes after a[2][0] is changed. Note The slice() method is a shallow copy.
Array.prototype.concat()
var arr = ['11', '22', '33'];
var arrCopy = arr.concat();
arr[0] = '666'
console.log(arr) //["666", "22", "33"]
console.log(arrCopy) //["11", "22", "33"]
Copy the code
To sum up, Array’s slice and concat methods are not really deep copies. They are deep copies of the first layer elements of Array, while Array’s second slice and concat methods are copy references. So, Array’s slice and concat methods are shallow copies.
Deep copy
What is deep copy?
Deep copy copies all attributes and dynamically allocated memory to which the attributes point. Deep copy occurs when an object is copied along with the object it references. Deep copy is slower and more expensive than shallow copy. The two objects do not affect each other.
JSON. Stringify and JSON. The parse
Parse converts strings into new objects using json.stringify.
Function deepClone(obj) {let _obj = json.stringify (obj); function deepClone(obj) {let _obj = json.stringify (obj); let objClone = JSON.parse(_obj); return objClone; }Copy the code
Var a = {name: 'json.parse (a)); var a = {name:' json.parse (a)); var a = {name: 'json.parse (a)); A.name = 'li si '; Address = 'Taiyuan, Shanxi' console.log(a) console.log(b)Copy the code
This method can only be used for objects that can be converted to JSON, but not if the object contains functions or RegExp.
Extend ();
let $ = require('jquery');
let obj1 = {
a: 1,
b: {
f: {
g: 1
}
},
c: [1, 2, 3]
};
let obj2 = $.extend(true, {}, obj1);
Copy the code
2. Array deep copy
let a = [0, "1", [2, 3]]; let b = JSON.parse(JSON.stringify( a.slice(1) )); console.log(b); / / [" 1 ", [2, 3]]Copy the code
a[1] = "99"; a[2][0] = 4; console.log(a); // [0, "99", [4, 3]] console.log(b); / / [" 1 ", [2, 3]]
3. Lodash.clonedeep () implements deep copy
let _ = require('lodash');
let obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
let obj2 = _.cloneDeep(obj1);
Copy the code
4. Implement deep copy recursively
function _deepClone(source) { let target; if (typeof source === 'object') { target = Array.isArray(source) ? [] : {} for (let key in source) { if (source.hasOwnProperty(key)) { if (typeof source[key] ! == 'object') { target[key] = source[key] } else { target[key] = _deepClone(source[key]) } } } } else { target = source } return target }Copy the code
conclusion
Assign ({},srcObj) if the Object attribute value is a simple type (such as String, number), assign({},srcObj). The resulting new object is a deep copy; If the attribute value is an object or some other reference type, it is actually shallow-copied for that object. When there are only primary attributes in an object and no secondary attributes,Objec*t.assign({},srcObj) ' 'and extension operator (...)
Is a deep copy, but if there is an object in the object, this method is a shallow copy after the secondary property.