“This is the sixth day of my participation in the First Challenge 2022. For details: First Challenge 2022”

Introduction to the

Interview can be JS assignment copy, shallow copy, deep copy of the problem is very few. Today I review again, I hope to help you.

variable

To understand shallow and deep copy in JS, you need to be familiar with variable types, which are divided into basic data types (value types) and reference data types (complex data types). Values for basic data types are stored directly in stack memory, whereas stack memory for reference data types holds memory addresses and values are stored in heap memory.

Basic data types include Number, String, Boolean, Null, Undefined, Symbol, BigInt, and reference data types include Object, Array, Date, Error, Function, and RegExp.

The storage for reference data types is shown below

Copy assignment

Assignment copy is what we usually call = assignment. Assignment copies are divided into basic data type assignment copies and reference data type assignment copies.

Assignment copies of primitive data types do not affect each other.

let name = "randy";
let name2 = name; // Assign name to name2
name = "demi"; // Change name to 'demi'
console.log(name); // demi
console.log(name2); // randy
Copy the code

An assignment copy of a reference data type is an address reference, meaning that two variables refer to the same address in heap memory, so they have an effect on each other.

const user = { name: "randy" };
const user2 = user;
user.name = "demi";
console.log(user.name); // demi
console.log(user2.name); // demi
Copy the code

What if I don’t want to refer to copies of data types affecting each other? We need to use our shallow copy deep copy knowledge. Shallow copy and deep copy apply only to reference data. Basic data types do not have shallow copy and deep copy.

Shallow copy

Shallow copy copies only the first layer properties of the original object. That is, if the property is a primitive data type, the value of the primitive type is copied. If the attribute is a reference data type, the memory address of the reference type is copied.

Implement shallow copy manually

// Shallow copy obj
const shallowCopy = (obj) = > {
  if (typeof obj === 'object'&& obj ! = =null) {
    let copy = Array.isArray(obj) ? [] : {};
    // Iterate over the old object/array, assigning the first level property to the new object/array
    for (var p in obj) {
      copy[p] = obj[p]
    }
    // The new object returned is the shallow-copied object
    return copy
  } else {
    // If it is a basic type, return it directly
    return obj
  }
}
Copy the code

The shallow copy method is commonly used

Common shallow copy methods in JS include object.assign (), extension operator {… Obj} and Array array.concat (), array.slice (), array.from (), extension operator {… Clone methods for arR} and Lodash libraries.

So let me give you an example

const user = {
  name: "randy".address: { province: "Hunan".city: "Mimi,"}};const user2 = Object.assign({}, user);
constuser3 = { ... user }; user.name ="demi";
user.address.province = "Shanghai";
console.log("user:", user); / / {name: "demi, address: {province: 'Shanghai, city:' mi - ronaldo '}}
console.log("user2:", user2); / / {name: "randy", address: {province: 'Shanghai, city:' mi - ronaldo '}}
console.log("user3:", user3); / / {name: "randy", address: {province: 'Shanghai, city:' mi - ronaldo '}}

const arr = ["randy", { province: "Hunan".city: "Mimi," }];
const arr2 = arr.concat([]);
const arr3 = arr.slice();
const arr4 = Array.from(arr);
const arr5 = [...arr];

arr[0] = "demi";
arr[1].province = "Shanghai";
console.log("arr:", arr); / / {name: "demi, address: {province: 'Shanghai, city:' mi - ronaldo '}}
console.log("arr2:", arr2); / / {name: "randy", address: {province: 'Shanghai, city:' mi - ronaldo '}}
console.log("arr3:", arr3); / / {name: "randy", address: {province: 'Shanghai, city:' mi - ronaldo '}}
console.log("arr4:", arr4); / / {name: "randy", address: {province: 'Shanghai, city:' mi - ronaldo '}}
console.log("arr5:", arr5); / / {name: "randy", address: {province: 'Shanghai, city:' mi - ronaldo '}}
Copy the code

Deep copy

To solve the shallow copy problem will use our deep copy!

A deep copy is a complete copy of the object in memory, creating a new memory space in the heap, completely independent of the original object. Modifying the new object does not affect the original object.

Implement deep copy manually

// Recursive shallow copy
const _shallowCopy = (obj) = > {
  const copy = Array.isArray(obj) ? [] : {};
  for (let p in obj) {
    if (typeof obj[p] === "object") {
      // Object type, continue recursive shallow copy
      copy[p] = _shallowCopy(obj[p]);
    } else{ copy[p] = obj[p]; }}return copy;
};

/ / copy
const deepCopy = (obj) = > {
  if (typeof obj === "object"&& obj ! = =null) {
    // If it is a reference type, make a recursive shallow copy
    return _shallowCopy(obj);
  } else {
    // If it is a basic type, return it directly
    returnobj; }};Copy the code

The deep-copy method is commonly used

Parse (json.stringfy (obj)) or the deepClone method of the LoDash library.

So let me give you an example

/ / object
const user = {
  name: "randy".address: { province: "Hunan".city: "Mimi,"}};const user2 = JSON.parse(JSON.stringify(user));
user.name = "demi";
user.address.province = "Shanghai";
console.log("user:", user); / / {name: "demi, address: {province: 'Shanghai, city:' mi - ronaldo '}}
console.log("user2:", user2); / / {name: "randy", address: {province: 'in hunan province, city,' Mimi ROM '}}

/ / array
const arr = ["randy", { province: "Hunan".city: "Mimi," }];
const arr2 = JSON.parse(JSON.stringify(arr));
arr[0] = "demi";
arr[1].province = "Shanghai";
console.log("arr", arr); / / {name: "demi, address: {province: 'Shanghai, city:' mi - ronaldo '}}
console.log("arr2", arr2); / / {name: "randy", address: {province: 'in hunan province, city,' Mimi ROM '}}
Copy the code

extension

Parse (json.stringfy (obj)) is useful, but there are a few points to note

  1. undefined,Arbitrary functionAs well assymbolValue is ignored during serialization (when it appears in an attribute value of a non-array object) or is converted tonull(when appearing in an array).
  2. function,undefined,SymbolReturns when converted separatelyundefined.
  3. All tosymbolProperties that are property keys are completely ignored.
  4. DateDate is calledtoJSON()Convert it tostringString (same asDate.toISOString()), so it is treated as a string.
  5. The error object is converted to an empty object.
  6. The re is converted to an empty object.
  7. NaNInfinityThe value of the format andnullWill be regarded asnull.
  8. Executing this method on objects that contain circular references (objects that refer to each other in an infinite loop) throws an error.
  9. When trying to switchBigIntThe value of the type is thrownTypeError ("BigInt value can't be serialized in JSON").

Undefined, arbitrary functions, and symbol values are ignored during serialization (when appearing in an attribute value of a non-array object) or converted to NULL (when appearing in an array).


const obj4 = {
  a: undefined.b: function say() {},
  c: Symbol(123),};const str4 = JSON.stringify(obj4);
console.log(str4); / / {}

const obj5 = [undefined.function say() {}, Symbol(123)];
const str5 = JSON.stringify(obj5);
console.log(str5); // [null,null,null]
Copy the code

Function, undefined, and Symbol are converted separately to return undefined.

console.log(
  JSON.stringify(Symbol(123)),
  JSON.stringify(undefined),
  JSON.stringify(function say() {}));// undefined undefined undefined
Copy the code

All properties with symbol as the property key are completely ignored.

const s1 = Symbol(a);const obj6 = { a: 1.b: 2, [s1]: 3 };
console.log(JSON.stringify(obj6)); // {"a":1,"b":2}
Copy the code

Date the Date is converted to a string by calling toJSON() (same as date.toisostring ()), so it is treated as a string.

const obj7 = { a: 1.b: 2.c: new Date() };
console.log(JSON.stringify(obj7)); / / {" a ": 1," b ": 2," c ":" the 2022-02-17 T06: now. 145 z}"
Copy the code

The error object is converted to an empty object.

/ / 5,
const obj8 = { a: 1.b: 2.c: new Error("error")};console.log("Errors are converted to empty objects:".JSON.stringify(obj8)); // {"a":1,"b":2,"c":{}}
Copy the code

The re is converted to an empty object.

const obj9 = { a: 1.b: 2.c: new RegExp("\\d"."i")};console.log("The re is converted to an empty object:".JSON.stringify(obj9)); // {"a":1,"b":2,"c":{}}
Copy the code

Values and nulls in NaN and Infinity formats are treated as null.

const obj10 = { a: 1.b: 2.c: NaN.d: Infinity.e: null };
console.log(JSON.stringify(obj10)); // {"a":1,"b":2,"c":null,"d":null,"e":null}
Copy the code

Executing this method on objects that contain circular references (objects that refer to each other in an infinite loop) throws an error.

// const obj11 = {};
// const obj12 = { a: obj11 };
// obj11.a = obj12;
// console.log(JSON.stringify(obj12));
Copy the code

TypeError is raised when attempting to convert a value of type BigInt (“BigInt value can’t be serialized in JSON”).

// const obj11 = { a: 1, b: 2, c: BigInt("12222222222222222222222") };
// console.log(" Values of type BigInt will raise TypeError: ", json.stringify (obj11));
Copy the code

Well, about JS assignment copy, shallow copy, deep copy, the author has spoken, friends whether understand? Finally, thank you for your patience.

Afterword.

This article is the author’s personal study notes, if there are fallacies, please inform, thank you! If this article helped you, please give it a thumbs up