This is the ninth day of my participation in the August More text Challenge. For details, see: August More Text Challenge

Today when doing an operational form function meet a problem, the form of the data from three kinds of form, I use a dialog popup layer, nested dynamic component implementation of this function, I design is each form to maintain their form data, when click submit, to the current table data, submit to the parent component of tabular data object.

Problem at this time, I added in the second, the second was covered in the first data, two lines has occurred in the form of a second data, make a little analysis, detect the reason may be because the shallow copy, this is my real business, business exceptions due to shallow copy for the first time, so the record resolution process, And review the principles and problems of deep and shallow copying.

Shallow copy

Let’s start with a shallow copy case

Let a =,1,2,3,4 [0], let b = a; console.log(a===b); //true a[0]=1; console.log(b); // 1,1,2,3,4Copy the code

If b copies a, why do I change array A and array B also changes array A? I can’t help but think about this, so I need to introduce the concept of basic data types and reference data types.

Basic data types and reference data types

Basic data types:

Number, String, Boolean, Null, and Undefined. Basic data types are accessed by value because you can directly manipulate the actual values stored in variables. The following figure illustrates the process of this basic data type assignment:

Reference type data:

Object type: Object, Array, Function, Data, etc.

  1. Javascript’s reference data types are objects that are stored in heap memory.
  2. Unlike other languages, you cannot directly access locations in the heap memory space and manipulate the heap memory space. You can only manipulate the reference address of an object in stack memory. So, the reference type data in stack memory is actually the reference address of the object in heap memory. Using this reference address, objects in the heap memory can be found quickly.

Let’s demonstrate the process of assigning a reference datatype:

Summarize the difference between

1. Different memory allocation mechanisms bring different access mechanisms when declaring variables

  1. Raw values: Simple segments of data stored in a stack, that is, their values are stored directly where variables are accessed.

This is because these primitive types occupy a fixed amount of space, so they can be stored in a smaller area of memory – the stack. This storage facilitates quick lookup of the variable’s value.

  1. Reference value: an object stored in the heap, that is, a value stored in a variable is a pointer to the memory address where the object is stored.

This is because: the size of the reference value changes, so you can’t put it on the stack, otherwise it will slow down variable lookup. Instead, the value placed in the stack space of a variable is the address that the object is stored in the heap. The size of the address is fixed, so storing it on the stack has no negative impact on variable performance.

  1. Reference value: when a variable that holds the memory address of an object is copied to another variable, the memory address is assigned to the new variable.
  2. Javascript does not allow direct access to objects stored in the heap, so when you access an object,

First, you get the address of the object in the heap, and then you get the value of the object based on that address. This is called access by reference. 5. Values of primitive types are directly accessible.

2. Differences when copying variables

  1. Original value: When a variable that holds the original value is copied to another variable, a copy of the original value is assigned to the new variable. After that, the two variables are completely independent; they just have the same value.

That is, both variables refer to the same object in the heap, and changes made to either of them are reflected in the other. 2. It is important to understand that when you copy an object, you do not create an identical object in the heap, just a variable that holds a pointer to the object. There’s an extra pointer

3. Differences in parameter passing (the process of copying arguments to parameters)

First, let’s be clear: Arguments to all functions in ECMAScript are passed by value. But why is there still a difference when it comes to the value of a primitive type versus a reference type? Because of the difference in memory allocation.

  1. Raw value: just pass the value of the variable to the parameter, after which the parameter and the variable do not affect each other.
  2. Reference value: an object variable whose value is the memory address of the object in the heap, keep that in mind!

So the value it passes is the memory address, and that’s why any changes to this parameter inside the function are external, because they all point to the same object.

Deep copy

A deep copy does not copy the reference of the reference type, but copies all the values of the reference type to form a new reference type. In this way, there will be no misreference problem, and we can use the same data many times without worrying about conflicting data. So how to achieve deep copy?

The first: Utilize serialization

var obj1 = { a: 1, b: 2, c: 3 } var objString = JSON.stringify(obj1); var obj2 = JSON.parse(objString); obj2.a = 5; console.log(obj1.a); // 1 console.log(obj2.a); / / 5Copy the code

Summary: As you can see, there is no reference problem. Modifying the data in obj2 will not affect obj1, but it will cause some changes to the data. That’s because using json.stringify () and json.parse () it is not possible to copy undefined, function, RegExp and so on

Use object.assign (target, source)

 var obj1 = {
    a: 1,
    b: 2,
    c: ['a','b','c']
}
var obj2 = Object.assign({}, obj1);
obj2.c[1] = 5;
console.log(obj1.c); // ["a", 5, "c"]
console.log(obj2.c); // ["a", 5, "c"]
Copy the code

Summary: As you can see, this is not a problem for a one-layer object, but if the object attributes correspond to other reference types and only the reference is copied, it is still a problem to modify

Third: use recursion

/ * * * * judge whether basic data type @ param value * / function isPrimitive (value) {return (typeof value = = = 'string' | | typeof value = = = 'number' | | typeof value = = = 'symbol' | | typeof value = = = 'Boolean')} / * * * to judge whether a js object * @ param value * / function IsObject (value) {return Object. The prototype. ToString. Call (value) = = = '[Object Object]'} / deep copy a value * * * * @ param value * / Export default function cloneDeep(value) { Const memo = {} function baseClone(value) {let res // If (isPrimitive(value)) {return value // If (isPrimitive(value)); } else if (array.isArray (value)) {res = [...value]} else if (isObject(value)) {res = {... Value}} // Check whether the property values of our shallow copy of the object are reference data types. ForEach (key => {if (typeof res[key] === 'object' && res[key]! == null) {// here we use memo to record the address of the reference that has been copied. If (memo[res[key]]) {res[key] = memo[res[key]]} else {memo[res[key]] = res[key] res[key] = baseClone(res[key]) } } }) return res } return baseClone(value) }Copy the code

Summary: This encapsulation method can be used to solve the problem perfectly