Data type and copy

In daily development, we often conduct some data processing. When processing reference data types (such as data and objects, etc.), if the original data is not cloned, the original data will be damaged. Sometimes, if the data transmission link is deep, it will be difficult to locate the problem.

The distinction between basic data types and reference data types should therefore be something every front-end developer should know by heart.

What are the data types in JS

ECMAScript has two distinct classes of values: base data types and reference data types.

String Number Boolean Null Undefined Symbol(ES2015 added) Bigint(ES2020 added)

Reference data types: basic Object and Array Function Date RegExp…

The difference between base data types and reference data types

We know that we have stacks and heaps in memory.

Basic types are stored in stack memory, and these types have a fixed amount of space in memory, accessed by value.

Reference types have variable values, so memory addresses are stored in stack memory and values are stored in heap memory. When a variable of a reference type is queried, the memory address is read from the stack, and then the address is used to find the value in the heap for reference access.

In a computer’s data structure, the stack is faster than the heap. Object is a complex and extensible data type. In order not to affect the efficiency of the stack, their values are stored in the heap and retrieved by reference from the memory address in the stack.

The assignment

Assignment is the process of assigning a value or object to a variable.

Assignment of a basic datatype. After assignment, the two variables do not affect each other.

let a = "value";
let b = a;
console.log(a, b); // value, value

a = "changed value";
console.log(a, b); // changed value, value
Copy the code

A variable that refers to a data type is an assignment, two variables have the same reference, the same memory address, point to the same object, and the two variables affect each other.

const a = { key: "value" };
const b = a;
console.log(a, b); // { key: "value" }, { key: "value" }

b.key = "changed value";
console.log(a, b); // { key: "changed value" }, { key: "changed value" }
Copy the code

In daily development, you don’t want variable A to change and affect variable B, so shallow and deep copies are used.

Difference between shallow copy and deep copy

Shallow copy: Creates a new object that has an exact copy of the original object’s property values. If the property is of a primitive type, the value of the primitive type is copied. If the property is a reference type, the memory address is copied, so if one object changes the address, the other object will be affected. In simple terms, shallow copy can only solve the first layer of reference problem, copy the first layer of basic types and the first layer of reference type address.

Deep copy: The deep copy copies all attributes and the dynamically allocated memory specified by the attributes. The deep copy is slower and more expensive than the shallow copy. However, the two objects do not affect each other after the deep copy.

Common method of shallow copy

  1. Object.assign()

Used to copy the value of all enumerable properties from one or more source objects to the target object, with the return value being the target object

const obj = {
  hello: "world".info: {
    name: "conrad",}};const clonedObj = Object.assign({}, obj);

console.log(obj); // { hello: 'world', info: { name: 'conrad' } }
console.log(clonedObj); // { hello: 'world', info: { name: 'conrad' } }

obj.hello = "javascript";
obj.info.name = "merry";

console.log(obj); // { hello: 'javascript', info: { name: 'merry' } }
console.log(clonedObj); // { hello: 'world', info: { name: 'merry' } }
Copy the code
  1. Expansion operatorSpread

Similar to Object.assign(), the above example uses Spread in the same way as object.assign ().

const obj = {
  hello: "world".info: {
    name: "conrad",}};constclonedObj = { ... obj };console.log(obj); // { hello: 'world', info: { name: 'conrad' } }
console.log(clonedObj); // { hello: 'world', info: { name: 'conrad' } }

obj.hello = "javascript";
obj.info.name = "merry";

console.log(obj); // { hello: 'javascript', info: { name: 'merry' } }
console.log(clonedObj); // { hello: 'world', info: { name: 'merry' } }
Copy the code
  1. Some of Array’s native methods are likeslice() concat()Etc.
const arr = [1, { name: "conrad"},3.4]].const clonedArr1 = arr.map((item) = > item);
const clonedArr2 = arr.slice(1);

console.log(arr); // [ 1, { name: 'conrad' }, [ 3, 4 ] ]
console.log(clonedArr1); // [ 1, { name: 'conrad' }, [ 3, 4 ] ]
console.log(clonedArr2); // [ { name: 'conrad' }, [ 3, 4 ] ]

arr[0] = 100;
arr[1].name = "merry";
arr[2] [0] = 300;

console.log(arr); // [ 100, { name: 'merry' }, [ 300, 4 ] ]
console.log(clonedArr1); // [ 1, { name: 'merry' }, [ 300, 4 ] ]
console.log(clonedArr2); // [ { name: 'merry' }, [ 300, 4 ] ]
Copy the code

The shallow copy only copies the memory addresses of the basic type and reference type of the first layer. Therefore, use caution during development to ensure that cloned data is not affected.

Common methods of deep copy

  1. JSON.parse(JSON.stringify(object))

Using json.parse (json.stringify (object)) to make a deep copy of an object does not affect the original object and can be used for simple data and scenarios in daily development. But there are some problems:

  • ignoreundefined
  • ignoreSymbol
  • Can’t handleBigint
  • Non-serializable function
  • Cannot solve the problem of looping reference objects
  • Unable to clone correctlyDateobject
  • Cannot handle regexRegExpobject
const cir = {};
cir.cir = cir;

const obj = {
  a: "1".b: 1.c: true.d: null.e: undefined.f: Symbol("f"),
  TypeError: Do not know how to serialize a BigInt
  h: {},
  i: function () {
    return "i";
  },
  j: () = > {
    return "j";
  },
  k: Date(),
  l: /^\d&/.// Cir, // Adding this line causes an error: TypeError: Converting circular structure to JSON
};

console.log(JSON.stringify(obj)); / / {" a ":" 1 ", "b" : 1, "c" : true, "d", null, "h" : {}, "k" : "Thu Jul 22 2021 12:30:21 GMT + 0800 (China standard time)", "l" : {}}
console.log(JSON.parse(JSON.stringify(obj)));
{/ * * a: '1', b: 1, c: true, d: null, h: {}, k: 'Thu Jul 22 2021 12:30:21 GMT + 0800 (China standard time)', l: {}} * /
Copy the code
  1. lodashthecloneDeep()

How to implement a deep copy

Deep copy can be divided into two simple steps: recursive + shallow copy.

In shallow copy, you need to determine the data type of the copied attribute value. Different processing methods are required for different data types. And also need to consider the circular reference, recursive stack burst and other problems. The next article will detail how to implement a deep copy from scratch.

reference

Wood – Yang front-end advanced -JavaScript in-depth storage space detailed diagrams

Woo-yang front-end advancements – details the differences between assignment, shallow copy and deep copy

I welcome exchange and correctionCopy the code