本質上的緣由是對象引用的是地址,直接賦值會吧引用地址也複製給新值。
淺複製只會將對象的各個屬性進行依次複製,會把引用地址也複製。
深拷貝是會遞歸源數據,吧新值得引用地址給換掉。數組
入口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等遞歸