浅拷贝和深拷贝

本质上的原因是对象引用的是地址,直接赋值会吧引用地址也复制给新值。
浅复制只会将对象的各个属性进行依次复制,会把引用地址也复制。
深拷贝是会递归源数据,吧新值得引用地址给换掉。

lodash的cloneDeep

入口

<!-- 这两个flog是因为baseClone会被很多方法给调用,这两个适用于区分一些操作 --><!-- 1是是否深度复制,4是是否复制 Symbols类型-->const CLONE_DEEP_FLAG = 1const CLONE_SYMBOLS_FLAG = 4function cloneDeep(value) {  return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG)}

核心逻辑

function baseClone(value, bitmask, customizer, key, object, stack) {  let result  const isDeep = bitmask & CLONE_DEEP_FLAG  const isFlat = bitmask & CLONE_FLAT_FLAG  const isFull = bitmask & CLONE_SYMBOLS_FLAG  if (customizer) {    result = object ? customizer(value, key, object, stack) : customizer(value)  }  if (result !== undefined) {    return result  }  if (!isObject(value)) {    return value  }  // 判断是否数组  const isArr = Array.isArray(value)  // 获取constructor  const tag = getTag(value)  if (isArr) {    // 初始化一个长度和源相等的数组    result = initCloneArray(value)    // 不是deep就直接复制了事    if (!isDeep) {      return copyArray(value, result)    }  } else {    const isFunc = typeof value == 'function'      // Buffer.isBuffer, 对于buffer对象就直接复制了事    if (isBuffer(value)) {      return cloneBuffer(value, isDeep)    }    if (tag == objectTag || tag == argsTag || (isFunc && !object)) {      // 是否需要继承proto      result = (isFlat || isFunc) ? {} : initCloneObject(value)      if (!isDeep) {        // 这里deepclone的isFlat是0,走copySymbols,这个方法主要是复制源上的Symbols        return isFlat          ? copySymbolsIn(value, copyObject(value, keysIn(value), result))          : copySymbols(value, Object.assign(result, value))      }    } else {      // 如果是func或error, WeakMap就直接返回了      if (isFunc || !cloneableTags[tag]) {        return object ? value : {}      }      // 对tag位true的类型进行clone      result = initCloneByTag(value, tag, isDeep)    }  }  // Check for circular references and return its corresponding clone.  // 检查循环引用并返回其相应的克隆。  stack || (stack = new Stack)  const stacked = stack.get(value)  if (stacked) {    return stacked  }  stack.set(value, result)  // 对map递归clone  if (tag == mapTag) {    value.forEach((subValue, key) => {      result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack))    })    return result  }  // 对set递归调用  if (tag == setTag) {    value.forEach((subValue) => {      result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack))    })    return result  }  // 是否是TypedArray类型  if (isTypedArray(value)) {    return result  }  const keysFunc = isFull    ? (isFlat ? getAllKeysIn : getAllKeys)    : (isFlat ? keysIn : keys)  const props = isArr ? undefined : keysFunc(value)  arrayEach(props || value, (subValue, key) => {    if (props) {      key = subValue      subValue = value[key]    }    // Recursively populate clone (susceptible to call stack limits).    assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack))  })  return result}

数组这里主要是会有个exec的特殊数组

function initCloneArray(array) {  const { length } = array  const result = new array.constructor(length)  // Add properties assigned by `RegExp#exec`.  // RegExp.exec返回的特殊数组  if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {    result.index = array.index    result.input = array.input  }  return result}

其他方法

Underscore库或JSON.parse等