JavaScript 深拷贝与浅拷贝

1,413 阅读3分钟

前言

对于很多初次接触JavaScript的读者来说,想要实现对象的拷贝/复制,就是单纯的使用赋值语句(=)来实现需求。但是,这样的方式是不全面的,这样的方法对于简单类型的数据来说是没有问题的,但是如果是对于像对象这样的复杂的数据类型来说,这样的实现方式有就会给你带来意想不到的问题。那么,如果不能简单的用赋值语句实现对象的拷贝(复制),我们应该用什么样的方式呢?这个,就是深拷贝和浅拷贝的意义所在了。

1、对深拷贝和浅拷贝的初步认识

深拷贝和浅拷贝只针对像 Object, Array 这样的复杂对象的。简单来说,浅拷贝只拷贝一层对象的属性,而深拷贝则递归拷贝了所有层级。

对于字符串类型,浅拷贝是对值的复制,对于对象来说,浅拷贝是对对象地址的复制,并没有开辟新的栈,也就是复制的结果是两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会改变,而深拷贝则是开辟新的栈,两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。

2、深拷贝与浅拷贝的区别

虽然两者都是对内容的拷贝,但是拷贝的内容的不同是区分两者的关键,而这个不同主要体现在对Object和Array这样的复杂对象。最直接的原因是诸如字符串这样简单的类型的拷贝就是内容的复制,并不会有别的什么深层次的东西,但是对于Objcet和Array这样复杂的类型,主要是由于对象的复制是基于对对象的地址的复制而不是整体内容的复制(对象包含了key ,value)。

简而言之:浅拷贝之后的对象实际上都是同一个对象,而深拷贝之后的对象都是除了内容相同以外完全无关的对象。 3、浅拷贝存在的缺陷   通过一个实例来说明使用浅拷贝对对象进行复制会导致哪些问题,从而正确认识使用深拷贝和浅拷贝的重要意义。

var obj = { a:1, arr: [2,3] };
var shallowObj = shallowCopy(obj);
 
function shallowCopy(src) {
  var dst = {};
  for (var prop in src) {
    if (src.hasOwnProperty(prop)) {
      dst[prop] = src[prop];
    }
  }
  return dst;
}
 
/*
    导致的结果就是:
        对shallowObj对象的更改也会影响到原对象obj,即所谓的牵一发而动全身。
*/
shallowObj.arr[1] = 5;
obj.arr[1]   // = 5

总结

对于简单数据类型的赋值都是浅拷贝,深拷贝只针对复杂数据类型,如对象。 浅拷贝 只是指向相同的内存地址,深拷贝则不指向原来的内存地址。