chiyan-lin / code-snippet

the record of something snippety
1 stars 0 forks source link

deepClone #8

Open chiyan-lin opened 4 years ago

chiyan-lin commented 4 years ago
/*
 * @Description: 深拷贝
 * @Author: gaidy
 * @Date: 2019-09-28 18:20:37
 * @LastEditTime: 2019-10-03 13:54:57
 */

function cycle (array, iteratee) {
  let index = -1
  const length = array.length
  while (++index < length) {
    iteratee(array[index], index)
  }
  return array
}

function type (target) {
  return Object.prototype.toString.call(target).match(/\[object\s(.+)\]/)[1]
}

function getInit (target) {
  const Ctor = target.constructor
  return new Ctor()
}

function isObject (target) {
  const type = typeof target
  return target !== null && (type === 'object' || type === 'function')
}

function cloneFunction (func) {
  const bodyReg = /(?<={)(.|\n)+(?=})/m
  const paramReg = /(?<=\().+(?=\)\s+{)/
  const funcString = func.toString()
  if (func.prototype) {
    console.log('普通函数')
    const param = paramReg.exec(funcString)
    const body = bodyReg.exec(funcString)
    if (body) {
      console.log('匹配到函数体:', body[0])
      if (param) {
        const paramArr = param[0].split(',')
        console.log('匹配到参数:', paramArr)
        return new Function(...paramArr, body[0])
      } else {
        return new Function(body[0])
      }
    } else {
      return null
    }
  } else {
    return eval(funcString)
  }
}

function cloneSymbol (targe) {
  return Object(Symbol.prototype.valueOf.call(targe))
}

function cloneReg (targe) {
  const reFlags = /\w*$/
  const result = new targe.constructor(targe.source, reFlags.exec(targe))
  result.lastIndex = targe.lastIndex
  return result
}

function clone (target, map = new WeakMap()) {
  if (!isObject(target)) {
    return target
  }

  let cloneTarget = type(target) === 'Object' ? getInit(target) : []

  // 解决循环引用的问题
  if (map.get(target)) {
    return map.get(target)
  }
  map.set(target, cloneTarget)

  // 克隆set
  if (type === 'Set') {
    target.forEach(value => {
      cloneTarget.add(clone(value, map))
    })
    return cloneTarget
  }

  // 克隆map
  if (type === 'Map') {
    target.forEach((value, key) => {
      cloneTarget.set(key, clone(value, map))
    })
    return cloneTarget
  }

  if (type === 'Function') {
    return cloneFunction(target)
  }

  if (type === 'RegExp') {
    return cloneReg(target)
  }

  if (type === 'Symbol') {
    return cloneSymbol(target)
  }

  cycle(Object.keys(target), (val, key) => {
    const tvType = type(target[val])
    // 处理引用类型的拷贝
    if (tvType === 'Object' || tvType === 'Array') {
      return (cloneTarget[val] = clone(target[val], map))
    }
    // 对于非引用直接赋值
    cloneTarget[val] = target[val]
  })

  return cloneTarget
}

// 简易 extend 

function extend (...args) {
  let clone = new args[0].constructor()
  const argsLen = args.length
  for(let arg = 0; arg < argsLen; arg++) {
      const target = args[arg]
      const targerType = type(target)
      if (targerType === 'Object' || targerType === 'Array') {
          cycle(Object.keys(target), (key, keyIndex) => {
              const item = target[key]
              const itemType = type(item)     
              if (itemType === 'Object' || itemType === 'Array') {
                  clone[key] = extend(item)
              } else {
                  clone[key] = item
              }
          })
      }
  }
  return clone
}

const field5 = [1, 2, 3]
const test = {
  field1: 1,
  field2: undefined,
  field3: 'ConardLi',
  field4: {
    child: 'child',
    child2: {
      child2: 'child2'
    }
  },
  field5
}
test.test = test

const rs = clone(test)
console.log('rs', rs)

field5[0] = 444
console.log('rs', rs)

// https://juejin.im/post/5d6aa4f96fb9a06b112ad5b1