本质上的缘由是对象引用的是地址,直接赋值会吧引用地址也复制给新值。
浅复制只会将对象的各个属性进行依次复制,会把引用地址也复制。
深拷贝是会递归源数据,吧新值得引用地址给换掉。数组
入口code
<!-- 这两个flog是由于baseClone会被不少方法给调用,这两个适用于区分一些操做 --> <!-- 1是是否深度复制,4是是否复制 Symbols类型--> 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等递归