赋值和深/浅拷贝的区别

155 阅读3分钟

当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。

浅拷贝:重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但拷贝前后对象的引用类型因共享同一块内存,会相互影响。

深拷贝:从堆内存中开辟一个新的区域存放新对象,对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。

浅拷贝的实现方式 1.Object.assign() Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。 2.函数库lodash的_.clone方法 该函数库也有提供_.clone用来做 Shallow Copy,后面我们会再介绍利用这个库实现深拷贝 3.展开运算符... 展开运算符是一个 es6 / es2015特性,它提供了一种非常方便的方式来执行浅拷贝,这与 Object.assign ()的功能相同。 4.Array.prototype.concat() 5.Array.prototype.slice()

深拷贝的实现方式 JSON.parse(JSON.stringify()) 这也是利用JSON.stringify将对象转成JSON字符串,再用JSON.parse把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。 这种方法虽然可以实现数组或对象深拷贝,但不能处理函数和正则,因为这两者基于JSON.stringify和JSON.parse处理后,得到的正则就不再是正则(变为空对象),得到的函数就不再是函数(变为null)了。

Immutable

Immutable是指一旦创建即不可变的数据,所有对Immutable对象进行的修改操作最终都会返回一个新的Immutable对象。其中实现的原理是持久化数据结构(Persistent Data Structure),即使用旧的数据创建新数据时保持旧的数据不变。

举例:正常对象a浅拷贝b后,修改b的属性c 如

let a = {c: 1};
let b = a;
b.c = 2;
console.log(a) // {c: 2}

会改变a的属性。 如果使用深拷贝如

let a = {c: 1};
let b = JSON.parse(JSON.stringify(a));
b.c = 2
console.log(a) // {c: 1}

则不会修改到之前a的属性。 但是有个缺点,就是当a很大的时候 深拷贝所占用的空间也会大。

使用immutable则可以不占用过大的空间同时保证复制后属性的修改是分离的(即不会影响到被复制的对象等)

immutable为了避免深拷贝带来的性能损耗,采用结构共享(Structure share)实现对数据的独立拷贝。即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。这样既可以用最小的代价实现对数据的独立拷贝,也不会对内存造成太大负担。