JavaScript中的拷贝(copy)

JavaScript中的拷贝分为两种: 深拷贝,浅拷贝。

为什么要使用深拷贝和浅拷贝呢?

如果现有var obj1 = {…}这个对象,想要复制对象obj1,一贯的做法就是obj2 = obj1,这时虽然obj2拥有了obj1的所有属性,但obj2却不是自由的,因为它的改动会影响到obj1,obj1的改动也会影响到obj2,这不是我们所希望的,所以要用到深拷贝和浅拷贝。

如何区分深拷贝与浅拷贝?

如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力。

  1. 浅拷贝(shallow copy):只复制指向某个对象的指针,而不复制对象本身,新旧对象共享一块内存;

  2. 深拷贝(deep copy):复制并创建一个一摸一样的对象,不共享内存,修改新对象,旧对象保持不变;

深拷贝与浅拷贝的拷贝对象

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

js基本类型的分类以及包含哪些?

基础类型:undefined 、 null、number、string、boolean、symbol

引用类型:object对象类型(Object 、Array 、Function 、Data)

而这两类数据存储分别是这样的:

a.基本类型–名值存储在栈内存中,例如let a=1;
在这里插入图片描述
当你b=a复制时,栈内存会新开辟一个内存,例如这样:
在这里插入图片描述

所以当你此时修改a=2,对b并不会造成影响,因为此时的b已自食其力,翅膀硬了,不受a的影响了。当然,let a=1,b=a;虽然b不受a影响,但这也算不上深拷贝,因为深拷贝本身只针对较为复杂的object类型数据。

b.引用数据类型–名存在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值,我们以上面浅拷贝的例子画个图:
在这里插入图片描述
当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值。
在这里插入图片描述
而当我们a[0]=1时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,这就是所谓的浅拷贝了。
在这里插入图片描述
那,要是在堆内存中也开辟一个新的内存专门为b存放值,就像基本类型那样,岂不就达到深拷贝的效果了。
在这里插入图片描述

深拷贝的实现

实现深拷贝主要有2种方法

(1)递归

(2)JSON.stringify结合JSON.parse

1.递归
这里的递归我们用jquery中的$.extend。

var tal = {name:'lili'};
	Cal=$.extend(true,{},tal);
tal.name='kiki';
console.log(tal,Cal);  //{name: "kiki"}{name: "lili"}

2.JSON.stringify结合JSON.parse

function test(obj){
    let _obj = JSON.stringify(obj),
    objClone = JSON.parse(_obj);
    return objClone
}
var tal = {name:'lili'};
Cal=test(tal);
Cal.name = 'kiki';
console.log(tal,Cal);  //{name: "lili"} {name: "kiki"}

注意

1.深拷贝中,副本和原对象不共享属性。

2.深拷贝递归的复制属性。

3.深拷贝的副本不会影响到原对象,反之亦然。

4.js中所有的原始数据类型默认执行深拷贝,比如Boolean, null, Undefined, Number,String等。

实际工作中,深拷贝(递归的对对象里每一层值和对象进行拷贝)应用很广泛,浅拷贝几乎只变成了一种概念,因为每一个需要clone的地方都是深拷贝。

发布了45 篇原创文章 · 获赞 157 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/liuyifeng0000/article/details/104545178