Some pits (deep and shallow copies) of vue parent-child component value transfer

Posted by Daleeburg on Mon, 20 Dec 2021 14:26:17 +0100

Reprinted in this article: https://www.yht7.com/news/116487

1. Problem description

The parent component passes the value to the child component. After the child component changes the passed value, the value of the parent component will also change.
This problem is relatively unpopular. Usually, if the component communication is relatively simple, it will not be encountered.

2. Cause analysis

Core: bidirectional binding
Two way binding is involved when parent-child components transfer values. When the value is of object type, the data source will be changed after value transfer.

Deep copy and shallow copy
This is discussed in detail below.

3. Solutions

My current solution is:
When transferring values, do not directly transfer the data source, but transfer values by copying or defining new variables.
Simply handle JSON Parse (JSON. Stringify (obj)), but this simple and crude method has its limitations. When the values are undefined, function and symbol, they will be ignored in the conversion process. Therefore, if there are three kinds of object values, using this method will lead to property loss.
The rest is the tool function of self writing deep copy, or directly with the help of third-party library functions, which will be discussed below.

4. Deep and light copies

Shallow and deep copies in JavaScript, Only for complex data types (Object, Array). Both shallow copy and deep copy can regenerate a copy of an existing Object. However, the Object instance is stored in heap memory and then manipulated through a reference value. Therefore, there are two cases when copying: copy reference and copy instance, which is also the difference between shallow copy and deep copy.
The following figure shows a shallow copy of JavaScript complex data types:

Shallow copy

Shallow copy is a copy reference. All copied references point to instances of the same object, and their operations will affect each other.

It is worth noting that: object Assgin () is a shallow copy. It can only copy the first layer in depth. It is a deep copy or a shallow copy. Because object Assign () copies the attribute value. If the property value of the source object is a reference to an object, it only points to that reference. (excerpt from MDN)

When MDN tells about assign, there is a typical example. Here is the article link.

The following is a list of the first type of shallow copy - copy references to the original object:

/**
 * Shallow copy of object
 */
var obj1 = {
 name:"wenyuan",
 age: 22
}
var obj2 = obj1;
obj2["job"] = "coder";
console.log(obj1); //Object {name: "wenyuan", age: 22, job: "coder"}
console.log(obj2); //Object {name: "wenyuan", age: 0, job: "coder"}


/* ------------------------- Gorgeous dividing line------------------------- */


/**
 * Shallow copy of array
 */
var arr1 = [1, 2, 3, "4"];
var arr2 = arr1;
arr2[1] = "test"; 
console.log(arr1); // [1, "test", 3, "4"]
console.log(arr2); // [1, "test", 3, "4"]

Next, let's look at the second type of shallow copy - source object copy instance, and its attribute object copy reference:
In this case, the outer source Object is a copy instance. If its attribute element is a complex data type (Object, Array), the inner element copies the reference.
Direct operation on the source object will not affect another object, but the value of the attribute of another object will be changed when operating on its attribute.

/**
 * Shallow copy of object
 * jQuery Of $ extend(a,b) or $ extend({},a,b)
 */
var obj1 = {
 name:"wenyuan",
 age: 22,
 social: {
  blog: "www.wenyuanblog.com"
 },
 skills: ["js", "html", "css", "python"]
}
var obj2 = $.extend({},obj1);
console.log(obj1 === obj2) // Output false, indicating that the outer array copy is an instance
console.log(obj1.social === obj2.social) // Output true, indicating that the attribute of Object type is a copy reference
console.log(obj1.skills === obj2.skills) // Output true, indicating that the attribute of Array type is a copy reference


/**
 * Shallow copy of object
 * ES6 Object Assign() and object extension operators
 */
var obj1 = {
 name:"wenyuan",
 age: 22,
 social: {
  blog: "www.wenyuanblog.com"
 },
 skills: ["js", "html", "css", "python"]
}
var obj2 = Object.assign({},obj1);
console.log(obj1 === obj2) // Output false, indicating that the outer array copy is an instance
console.log(obj1.social === obj2.social) // Output true, indicating that the attribute of Object type is a copy reference
console.log(obj1.skills === obj2.skills) // Output true, indicating that the attribute of Array type is a copy reference
var obj3 = {...obj1};
console.log(obj1 === obj3) // Output false, indicating that the outer array copy is an instance
console.log(obj1.skills === obj3.skills) // Output true, indicating that the attribute of Array type is a copy reference
console.log(obj1.skills === obj3.skills) // Output true, indicating that the attribute of Array type is a copy reference


/* ------------------------- Gorgeous dividing line------------------------- */


/**
 * Shallow copy of array
 * Array.prototype.slice()
 */
var arr1 = [{name: "wenyuan"}, {name: "Evan You"}];
var arr2 = arr1.slice(0);
console.log(arr1 === arr2); // Output false, indicating that the outer array copy is an instance
console.log(arr1[0] === arr2[0]); // Output true, indicating that the copied element is a reference


/**
 * Shallow copy of array
 * Array.prototype.concat()
 */
var arr1 = [{name: "wenyuan"}, {name: "Evan You"}];
var arr2 = arr1.concat();
console.log(arr1 === arr2); // Output false, indicating that the outer array copy is an instance
console.log(arr1[0] === arr2[0]); // Output true, indicating that the copied element is a reference


/**
 * Shallow copy of array
 * ES6 Object Assign() and object extension operators
 * Because arrays are special objects, this method in ES6 can also be used for arrays
 */
var arr1 = [{name: "wenyuan"}, {name: "Evan You"}];
var arr2 = Object.assign([],arr1)
var arr3 = { ...arr1 };
console.log(arr1 === arr2); // Output false, indicating that the outer array copy is an instance
console.log(arr1 === arr3); // Output false, indicating that the outer array copy is an instance
console.log(arr1[0] === arr2[0]); // Output true, indicating that the copied element is a reference
console.log(arr1[0] === arr3[0]); // Output true, indicating that the copied element is a reference

Deep copy

Reallocate memory in the heap, and create a new copy of all attributes of the source object to ensure that the reference graph of the deeply copied object does not contain any original object or any object on the object graph. The copied object is completely isolated from the original object and does not affect each other.

Here are some examples of deep copy:

/**
 * Deep copy of object
 * JSON.stringify()And JSON parse()
 * This deep copy is the simplest, but it has its limitations, as mentioned above
 */
var obj1 = {
 name:"wenyuan",
 age: 22,
 social: {
  blog: "www.wenyuanblog.com"
 },
 skills: ["js", "html", "css", "python"]
}
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj1 === obj2) // Output false, indicating that the outer array copy is an instance
console.log(obj1.social === obj2.social) // Output false, indicating that the attribute of Object type is also a copy instance
console.log(obj1.skills === obj2.skills) // Output false, indicating that the attribute of Array type is also a copy instance


/**
 * Deep copy of object
 * jQuery Of $ extend(true,a,b)
 */
var obj1 = {
 name:"wenyuan",
 age: 22,
 social: {
  blog: "www.wenyuanblog.com"
 },
 skills: ["js", "html", "css", "python"]
}
var obj2 = $.extend(true,obj1);
console.log(obj1 === obj2) // Output false, indicating that the outer array copy is an instance
console.log(obj1.social === obj2.social) // Output false, indicating that the attribute of Object type is also a copy instance
console.log(obj1.skills === obj2.skills) // Output false, indicating that the attribute of Array type is also a copy instance


/**
 * Deep copy of object
 * You can also write a function implementation by yourself, use recursion + judgment, and pay attention not to enter the dead loop
 * There are no examples here. I have compiled a blog on common tool functions before, which contains deep copy functions
 */


/**
 * Deep copy of object
 * lodash Of cloneDeep
 */
var obj1 = {
 name:"wenyuan",
 age: 22,
 social: {
  blog: "www.wenyuanblog.com"
 },
 skills: ["js", "html", "css", "python"]
}
var obj2 = _.cloneDeep(obj1);
console.log(obj1 === obj2) // Output false, indicating that the outer array copy is an instance
console.log(obj1.social === obj2.social) // Output false, indicating that the attribute of Object type is also a copy instance
console.log(obj1.skills === obj2.skills) // Output false, indicating that the attribute of Array type is also a copy instance

The above are the knowledge points of shallow copy and deep copy in JavaScript, which are recorded in the form of code for easy review.

This is the end of this article about some pitfalls in Vue parent-child component value transfer. For more information about Vue parent-child component value transfer, please search the previous articles of the cloud Haitian tutorial or continue to browse the relevant articles below. I hope you will support the cloud Haitian tutorial in the future!

Original link: https://www.wenyuanblog.com/blogs/vue-pit-child-component-value-changes-affect-the-parent-component-value.html
Reprint: https://www.yht7.com/news/116487

Topics: Vue