前端面试手撕系列——深浅拷贝


应用场景

我们知道对于拷贝来说,若为引用类型,则拷贝过程为引用拷贝,过程是让新对象所对应的栈中的地址指向旧对象。所以就不可以简单的赋值。也就有了浅拷贝和深拷贝一说。

一、浅拷贝

浅拷贝不考虑待拷贝对象的属性和方法是否为引用类型。
方法一、

var Clone=function(orign)
{
    var target= Array.isArray(orign)?[]:{}
    for(var key in orign)
    {
      if(orign.hasOwnProperty(key))//for in会遍历到原型链中的方法
      {
        target[key]=orign[key]
      }
    }
    return target
}

方法二、

function clone(orign)
{
  var target=Array.isArray(orign)?[]:{}
  //利用Object.keys+for ...of 剔除原型链
    for(var key of Object.keys(orign))
  {
    target[key]=orign[key]
  }
return target
}

方法三、

function clone(orign)
{
  var target=Array.isArray(orign)?[]:{}
   //利用Object.entires +for ...of 剔除原型链
  for(var [key,value] of Object.entries(orign) )
  {
    target[key]=value
  }
return target
}

方法四、

function clone(orign)
{
  return Object.assign(orign,{})
}

此外,像array上的slice方法、concat方法都属于浅拷贝。
实现过程主要是要去除原型链上的方法。浅拷贝存在的问题:

var person1={name:'Bob',
			age:19,	
			eat:{b:5}}
var person2=clone(person1)
person2.name='Alice'
person2.eat.b=6
console.log(person1,'----',person2)

在这里插入图片描述
根据上面的结果我们可以发现,在对拷贝出来的对象的基本类型进行修改时,待拷贝元素属性不会改变,而在对拷贝出来的对象的引用类型进行修改时,待拷贝元素属性还是发生了变化。那么我们就需要一种方法解决此类问题即深拷贝。

二、深拷贝

方法一:递归+考虑循环引用
深拷贝就是考虑我们的待拷贝对象的属性是否为引用类型,若为引用类型,就要递归处理。

const deepClones = (target, hash = new WeakMap()) => {

    if (typeof target !== 'object' || target === null) {
        throw ('sss')
    }
    if (hash.has(target)) {
        return hash.get(target)
    }
    let result;
    if (target instanceof Set) {
        result = new Set([...target])
    } else if (target instanceof Map) {
        result = new Map([...target])
    } else if (target instanceof Date) {
        result = new Date(target)
    } else if (target instanceof RegExp) {
        result = new RegExp(target)
    } else {
        result = Array.isArray(target) ? [] : {}
    }
    hash.set(target, result)
    for (let key of Object.keys(target)) {
        if (typeof target[key] === 'object' && target[key] !== null) {
            result[key] = deepClones(target[key], hash)
        } else {
            result[key] = target[key]
        }
    }
    return result;
}

方法二:JSON
JSON.stringfy可以将对象转为字符串(原始值),JSON.parse又可以将字符串转为对象,经过这一套操作就可以使拷贝后的对象与拷贝前的对象不指向一个区域。
但是JSON.parse之后不带任何方法,所以不常用:

var JSONfun=function(orign)
{
  var str=JSON.stringify(orign)
  var target=JSON.parse(str)
  return target

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值