js深拷贝与浅拷贝

老规矩先出一道题目,大家猜猜打印的结果是什么,然后我们一起探讨背后的原因。

var a=[1,2,3]
var b=a;
var c=[6,7,8]
b=c
b[0]=9
a=c
console.log(a)
console.log(b)
console.log(c)

先分析题目,我们会看到b首先对a进行了一次复制,接下来,b又复制了c,
最后b又改变其中的值。最后打印出a,b,c看看它们的结果有没有什么关联。
第一步:了解栈(stack)堆(heap)的概念,看看我们的a,b,c存在哪里。
stack为自动分配的内存空间,它由系统自动释放;而heap则是动态分配的内存,大小不定也不会自动释放。

第二步:存放在堆内存中的对象,变量实际保存的是一个指针,这个指针指向另一个位置。每个空间大小不一样,要根据情况开进行特定的分配。
当b=a时,b这个时候和a指向的是同样的地址,即此刻b=[1,2,3]

第三步:当堆中出现c的值,并且b=c,这个时候就是b复制c的值,b和c指向同一个地址。此时b的值为[6,7,8]

第四步:当b的值改变,b[0]=9,此时堆中的值为[9,7,8],此时c的值也为[9,7,8]

第五步:a复制c,此时a和b和c指向同一个地址。我们也会发现一个问题,那就是原来a中的值似乎还是存在堆中,
系统无法对它回收,但是我们却不知道通过什么方式找到它,但是它又占用了堆中的内存,这个就是内存泄露。

上面的就是一个典型的浅拷贝实现过程,拷贝对象里面的属性改变会影响原对象。那什么是深拷贝呢?深拷贝就是
拷贝对象里面的属性改变不会影响原对象的属性。
那如何实现一个深拷贝呢?

var array=[1,2,3]
function copy(array){
  let newArray=[]
  for(let item of array){
    newArray.push(item)
  }
  return newArray
}
var copyArray=copy(array)
copyArray[0]=100
console.log(array)
console.log(copyArray)

第一步:

第二步:newArray会复制array中的值,不过此时newArray中的值和array的值不在同一个堆中

第三步:newArray中的值改变了,但是array中的值不会改变。

同理我们可以实现对象的深拷贝

var newObject={}
var obj={
  name:'a',
  b:'student'
}
function copy(obj){
  for(let item in obj){
    newObject[item]=obj[item]
  }
  return newObject
}
var copyObj=copy(obj)
copyObj.name='b'
console.log(obj);//{name:'a',b:'student'}
console.log(copyObj)//{name:'b',b:'student'}

如果实现一个针对数组和对象的深拷贝是如何实现的呢?

function deepClone(s,t){
  var t={}||[]
  for(var i in s){
    if(typeof s[i]==='object'){
      t[i]=(s[i].constructor===Array)?[]:{}
      deepClone(s[i],t[i])
    }else{
      t[i]=s[i]
    }
  }
  return t
}
a.name={a:'aa'}
var b={}
b=deepClone(a,b)
b.name={a:'bb'}
console.log(a.name)
console.log(b.name)

如果不是单独针对数组或对象,而是能够通过数组对象和其他复杂的JSON形式的对象,我们怎么实现深拷贝呢?

var array=[
  {name:1},
  {name:2},
  {name:3}
]
var copyArray=JSON.parse(JSON.stringify(array))
copyArray[0].name=100
console.log('aa',array)
console.log('bb',copyArray)
原文地址:https://www.cnblogs.com/smart-girl/p/10051764.html