preface

Why implement it manually when you already have the tools?

If that doesn’t work, move on to the next replacement,

Why don’t you just read the documentation and use it?

The efforts of our predecessors have greatly reduced our development burden.

But I don’t think programming is a “it works” thing.

“Why does this work?”

“What the hell is this thing doing in there?”

“What side effects will it have if we put the implementation requirements on hold?”

What is “knowledge” anyway?

A small white study notes, “walk alone long way” from the favorite role of the silly dog Kerber.

The first one is about deep copy. Read Mr ConardLi’s article with some bold revisions:

  • Type supplementBigInt, andSymbolAs, existtypeof 1n === 'bigint'typeof Object(1n) === 'object'Two scenarios like this.
  • useReflect.ownKeys()To deal with the keySymbolThe scene.
  • To simplify thefunctionA copy of the.

The body of the

The general idea is as follows:

  1. First determine the value type and reference type, in the case of the value type directly return.
  2. Under the reference type, check whether traversal can be performed. If not, get its constructor and use the constructor to create a new return.
  3. Traversable case with the aid ofMap Check for circular referencesIf,MapIs already present in the
  4. Individual treatmentMapSetType.
  5. useReflect.ownKeys()Iterate over the key of an object, processing its value recursively.

The code is as follows:

/ / use the Object. The prototype. ToString. Call (target) to obtain the type
// Traversable type
const typeMap = '[object Map]';
const typeSet = '[object Set]';
const typeArray = '[object Array]';
const typeObject = '[object Object]';
const typeArguments = '[object Arguments]';
// The type cannot be traversed
const typeBoolean = '[object Boolean]';
const typeString = '[object String]';
const typeNumber = '[object Number]';
const typeBigInt = '[object BigInt]';
const typeDate = '[object Date]';
const typeError = '[object Error]';
const typeSymbol = '[object Symbol]';
const typeRegExp = '[object RegExp]';
const typeFunction = '[object Function]';

// Assemble an array of traversable types for the query below
const iterableTypes = [typeMap, typeSet, typeArray, typeObject, typeArguments];

// Process a copy of Symbol
Instead of using the new keyword, the Object() function is used to create a Symbol wrapper Object.
/ / use the Symbol. The prototype. The valueOf. Call () is used to obtain the value of the Symbol.
const getSymbol = function (target) {
  return Object(Symbol.prototype.valueOf.call(target));
};

// Process copies of RegExp, see implementation of Lodash.
Flags can be obtained with target.flags, but see MDN this method is poorly supported, so use the regular method to obtain the flags.
// lastIndex affects the index of the next match, so copy it too.
const getRegExp = function (target) {
  const regFlags = /\w*$/;
  const newReg = new RegExp(target.source, regFlags.exec(target));
  newReg.lastIndex = target.lastIndex;
  return newReg;
};

// Process copies of non-traversable types.
// Use target.constructor to get its constructor and return a new one.
function getUniterabletypes(target, type) {
  switch (type) {
    case typeBoolean:
    case typeString:
    case typeNumber:
    case typeBigInt:
    case typeDate:
    case typeError:
      return new target.constructor(target);
    case typeSymbol:
      return getSymbol(target);
    case typeRegExp:
      return getRegExp(target);
    default:
      return null; }}// check whether it is a utility function of reference type.
function isReference(target) {
  const type = typeof target;
  returntarget ! = =null && (type === 'object' || type === 'function');
}

/ / the main function
// There is a debate about Map or WeakMap in Mr. ConardLi's comments, but I don't know what it is because of my lack of knowledge
// Don't write like this if you don't understand it
function clone(target, map = new Map(a)) {
  // Non-reference type
  Boolean, number, bigint, string, date, undefined
  if(! isReference(target))return target;
  // Return function directly here, or see Mr. ConardLi's article
  if (typeof target === 'function') return target;

  // Reference type
  // Get its type
  let type = Object.prototype.toString.call(target);
  
  // Cannot continue traversal
  // null, Error, RegExp
  // Typeof === 'object' of the following wrapper objects, so it is filtered here when determining non-reference types
  // new Boolean, new Number, new String, new Date, Object(Symbol), Object(BigInt)
  if(! iterableTypes.includes(type)) {return getUniterabletypes(target, type);
  }
  
  // Continue traversal
  // map, set, array, object, args
  // Use its constructor to initialize, generate the corresponding Set, Map, etc
  let cloneTarget = new target.constructor();
  // Check for circular references
  if (map.get(target)) return map.get(target);
  map.set(target, cloneTarget);

  / / handle the Set
  // Note that the value is handled recursively when adding
  if (type === typeSet) {
    target.forEach((value) = > cloneTarget.add(clone(value, map)));
    return cloneTarget;
  }
  / / the Map processing
  // Note that the value of set is handled recursively
  if (type === typeMap) {
    target.forEach((value, key) = > cloneTarget.set(key, clone(value, map)));
    return cloneTarget;
  }
  // Iterate over the key, recursively processing its value
  // For the Symbol scenario, use reflect.ownkeys ()
  / / refer to nguyen half-stretching ES6 online documentation: https://es6.ruanyifeng.com/#docs/reflect#Reflect-ownKeys-target
  for (let key of Reflect.ownKeys(target)) {
    cloneTarget[key] = clone(target[key], map);
  }

  return cloneTarget;
}
Copy the code