Data is divided into basic data types (String, Number, Boolean, Null, Undefined, Symbol) and object data types.

1. Characteristics of basic data types: data stored directly in the stack

2, the characteristics of reference data type: store the object in the stack reference, the real data stored in the heap memory

I believe everyone is familiar with these two sentences, but this description is not rigorous, so I add the following description:

Basic data types: A variable corresponds to a value

2, reference data type: the variable corresponds to an address, the address refers to some object in the heap memory,

Note that the base data types are not always on the stack, only directly declared variables are.

Basic types are also placed on the heap if they are global. Primitive types, which are within reference types, are also placed on the heap.

A shallow copy is a bitwise copy of an object that creates a new object with a 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 memory address (reference type), the memory address is copied, so if a reference property in the original object changes the property of the object to which the pointer points, it affects another object.

The picture above says:

// Define the reference type refObj1
const refObj1 = [1.2.3];

// Define the original object
const SourceObj = {
    field1: 'source',
    refObj1,
}

// Perform a shallow copy operation to obtain CopiedObj
constCopiedObj = {... SourceObj};// The shallow copy method is described below

// Prints the copied object data
CopiedObj.field1; // 'source'
CopiedObj.refObj1; / / [1, 2, 3].

// Change the original object
SourceObj.field1 = 'no source';
SourceObj.refObj1[0] = 999;

// Prints the copied object data
CopiedObj.field1; // 'source' is unaffected
CopiedObj.refObj1; / / [999, 2, 3]; affected
Copy the code

You can copy the code above to the browser console and run it again so that you can see more clearly.

As shown in the code above, the shallow copy creates a new object and creates two new properties, copying in full the values of the formation property from the original object, including the values of the primitive type stored in Field1 and the addresses of an array stored in refObj1.

So, although there are two variables, sourceobj.refobj1 and copiedobj.refobj1, there is only one array object.

Shallow copy implementation

  • Object.assign() ****

    Object.assign({}, origin)

  • Spread expands for objects or arrays

    copyObj = { ... originObj };

    copyArr = [ ...originArr ];

  • for ... infor ... of

In a nutshell, the only difference between a deep copy and a shallow copy is that if the original object contains an attribute of a reference type, the object to which that attribute corresponds will be shallow copied again. Eventually, the original object is no longer associated with the copied object, just as copying and pasting a file is done, and nothing done to the source file affects the copied object.

Above talk

Deep copy implementation

  • JSON.parse(JSON.stringify(obj))throughTwo conversions of JSONDeep copy obJ, but cannot be copiedundefinedwithsymbolProperty, cannot be copiedA circular referenceobject
  • Use third-party tool library library
  • Implement a deep-copy function yourself

In theory, we only need to implement a full shallow copy, plus a recursive call to achieve a deep copy, nice ~

// Copy objects recursively, introducing maps to store copied objects and preventing circular references
function deepClone(source, map = new Map()) {
  // The basic data type returns a value directly
  if (typeofsource ! = ='object' || source === null) {
    return source;
  }
  // If it is already clone, return the clone object directly
  if (s = map.get(source)) {
    return s;
  }
  // Generate a Clone object
  const clone = Array.isArray(source) ? [] : {};
  // Store clone objects to prevent circular references
  map.set(source, clone);
  // recursive call
  for (const key of Object.keys(source)) {
    clone[key] = deepClone(source[key], map);
  }
  
  return clone;
}

Copy the code

Suggest oneself hand knock again, otherwise my knowledge or mine, can’t arrive in your brain ~

Take a look below

// Handle Map, Set, and Symbol types in addition
function deepClonePlus(source, map = new Map()) {
  if (typeofsource ! = ='object' || source === null) {
    return source;
  }
  if (s = map.get(source)) {
    return s;
  }
  const clone = Array.isArray(source) ? [] : {};
  map.set(source, clone);
  const allKeys = Reflect.ownKeys(source);

  for (const key of allKeys) {
    const value = a[key];
    const type = Object.prototype.toString.call(value);
    switch (type) {
      case '[object Object]':
      case '[object Array]': clone[key] = deepClone(source[key], map); break;
      case '[object Set]':
        const set = new Set(a); value.forEach(v= > set.add(deepClonePlus(v, map)));
        clone[key] = set;
        break;
      case '[object Map]':
        const temoMap = new Map(a); value.forEach((v, i) = > temoMap.set(i, deepClonePlus(v, map)));
        clone[key] = temoMap;
        break;
      case '[object Symbol]':
        clone[key] = Object(Symbol.prototype.valueOf.call(value)); break;
      default:
        clone[key] = new value.constructor(value); break; }}return clone;
}
Copy the code

Symbol to reintroduce javascript types

Recommended reading:

  • How to write code elegantly that doesn’t get beat up

  • Double grade (==) tips that beginners can’t miss

  • This refers to the arrow function

  • Differences and simplified implementations of Apply, Call, and bind

  • Enlightening lexical scope and scope chain explanation

  • A brief introduction to the execution context and execution stack

  • You may not know about variable promotion

  • In a few words with you to understand the “closure” | usage scenarios

  • Simple and clear “event loop /event loop” details

This article focuses on: front end foundation building journey from scratch.

If you learn something new, please give the author a thumbs up