cloneDeep
上一篇说了clone
,现在说一下跟深拷贝相关的cloneDeep
方法。
function clone(value) { return baseClone(value, false, true);}
function cloneDeep(value) { return baseClone(value, true, true);}
在arrayEach
中,再次用到了baseClone
,已经不适合再去简化相关逻辑了。我们删除掉浅拷贝的部分。
调用如下
cloneDeep([{a:1,b:2},3,4])
执行到了baseClone这里后,
function baseClone(value=[{a:1,b:2},3,4], isDeep=true, isFull=true, customizer, key, object, stack) { var result; if (result !== undefined) { return result; } if (!isObject(value)) { return value; } var isArr = isArray(value); if (isArr) { //初始化走这里 result为长度为3的空数组 result = initCloneArray(value); } else { var tag = getTag(value), isFunc = tag == funcTag || tag == genTag; if (tag == objectTag || tag == argsTag || (isFunc && !object)) { if (isHostObject(value)) { return object ? value : {}; } result = initCloneObject(isFunc ? {} : value); } } else { if (!cloneableTags[tag]) { return object ? value : {}; } result = initCloneByTag(value, tag, baseClone, isDeep); } } // Check for circular references and return its corresponding clone. stack || (stack = new Stack); var stacked = stack.get(value); if (stacked) { return stacked; } stack.set(value, result);// 这里存入stack if (!isArr) { var props = isFull ? getAllKeys(value) : keys(value); } // 第一次props 为undefined,value=[{a:1,b:2},3,4] arrayEach(props || value, function(subValue, key) { if (props) { key = subValue; subValue = value[key]; } // Recursively populate clone (susceptible to call stack limits). 递归克隆 //-1: subvalue => {a:1,b:2}, key => 0 // -2 subvalue => 3, key => 1 // -3 subvalue => 4, key => 2 assignValue(result, key, baseClone(subValue, isDeep, isFull, customizer, key, value, stack)); }); return result;}
arrayEach
中
//-1: subvalue => {a:1,b:2}, key => 0assignValue([undefined,undefined,undefined],0,baseClone({a:1,b:2},true,true,undefined,0,[{a:1,b:2},3,4],stack))
-1中,执行了baseClone({a:1,b:2},true,true,undefined,0,[{a:1,b:2},3,4],stack))
,
// value=> {a:1,b:2},result={}, if (!isArr) { var props = isFull ? getAllKeys(value) : keys(value); } // props => ['a','b'] arrayEach(props || value, function(subValue, key) { if (props) { key = subValue; // key=a,subValue=1 subValue = value[key]; // key=b,subValue=2 } assignValue(result, key, baseClone(subValue, isDeep, isFull, customizer, key, value, stack)); });
执行到assignValue这里,
assignValue({},'a',baseClone(1,true,true,....) = 1)assignValue({a:1},'b',baseClone(2,true,true,...)=2)
此时result为{a:1,b:2}
。
当然你会想,如果{a:1,b:2, c:{name:"10"}}
。
assignValue({a:1,b:2},'c',baseClone({name:"10"},true,true,...) )
baseClone({name:"10"},true,true,...)
- 它会初始化一个
{}
, - 因为是对象,props是存在的,key就是name,subValue就是10.
程序会继续执行
//-1: subvalue => {a:1,b:2}, key => 0assignValue([undefined,undefined,undefined],0,baseClone({a:1,b:2},true,true,undefined,0,[{a:1,b:2},3,4],stack))// -2 subvalue => 3, key => 1assignValue([{a:1,b:2},undefined,undefined],1,baseClone(3,true,true,undefined,1,[{a:1,b:2},3,4],stack))// -3 subvalue => 4, key => 2 assignValue([{a:1,b:2},3,undefined],2,baseClone(4,true,true,undefined,2,[{a:1,b:2},3,4],stack))
返回最终的result。
总结
cloneDeep
是需要递归拷贝的。我们可以总结下cloneDeep
。
- 如果需要被clone的是
number,string
等类型,直接返回值 - 如果是数组,首先会initClone出一个相同长度的空数组。
- 如果是对象,首先会initClone一个空对象。原型链上的除外。
对于数组或者对象中的属性,又会进行一个递归判断,如果该属性(数组便是index)的value是一个number,string
,执行结束,交出执行权。如果是数组或者对象,又会继续执行递归。