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 => 0
assignValue([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))
,
当然,这一步也会走到对应的arrayEach中。
// 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 => 0
assignValue([undefined,undefined,undefined],0,baseClone({a:1,b:2},true,true,undefined,0,[{a:1,b:2},3,4],stack))
// -2 subvalue => 3, key => 1
assignValue([{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
,执行结束,交出执行权。如果是数组或者对象,又会继续执行递归。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。