lodash 의 clone Deep 에 대한 분석

3674 단어 lodash자바 script
얕 은 복사 와 깊 은 복사
본질 적 인 이 유 는 대상 이 주 소 를 인용 하기 때 문 입 니 다. 직접 할당 회 죠? 인용 주소 도 새 값 으로 복사 합 니 다.얕 은 복 제 는 대상 의 각 속성 을 순서대로 복사 하고 인용 주소 도 복사 합 니 다.깊 은 복사 본 은 원본 데 이 터 를 되 돌려 줍 니 다. 새 주 소 를 참조 하여 바 꿀 수 있 습 니 다.
lodash 의 clone Deep
입구


const CLONE_DEEP_FLAG = 1
const CLONE_SYMBOLS_FLAG = 4

function 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 등

좋은 웹페이지 즐겨찾기