lodash的cloneDeep

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,执行结束,交出执行权。如果是数组或者对象,又会继续执行递归。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值