深拷贝(数组)浅拷贝

159 阅读3分钟

“携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天juejin.cn/post/712312…

拷贝对象(也是个面试题)

对象的深拷贝和浅拷贝的区别如下:

浅拷贝:仅仅复制对象的引用(引用指的是指针),而不是对象本身

深拷贝:采用递归的方式把复制的对象所引用的全部对象都复制一遍(包括子对象)

递归可以理解为是读取数据的一种方式

所有的赋值运算对于对象来说都是浅拷贝   b=a相当于把指针拷贝给了b

 

Js中的堆内存和占内存(涉及的基本都是对象的拷贝)

在js引擎中对变量的存储主要有两种位置,堆内存和栈内存。

在java中对内存的处理类似,栈内存主要用于存储各种基本类型的变量(已知大小),包括Boolean、Number、String、Undefined、Null,以及对象变量的指针,这是栈内存给人的感觉就像是一个线性排列的空间,每个小单元大小基本相等。

而堆内存主要负责对象Object这种变量类型的存储(未知大小,因为对象中有很多不确定的数据,后期可能还会修改它)

 

一般来说栈内存线性有序存储,容量小,系统分配效率高。而堆内存首先要在堆内存新分配存储区域,之后又要把指针存储到栈内存中。效率相对就要低一些了。垃圾回收方面,栈内存变量基本上用完就回收了,而堆内存中的变量因为存在很多不确定的引用,只有当所有调用的变量全部销毁之后才能回收。

堆内存是无序的

引用数据类型指的就是对象

直接=赋值时浅拷贝

基本类型——名值存储在栈内存中,例如let a=1;

栈内存
NameVal
a1

当你b=a复制时,栈内存会新开辟一个内存,例如下面这样

栈内存
NameVal
a1
1

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

 

引用数据类型——名存在栈内容中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向对象内容中的值。

**栈内存 **              ****堆内存

**名   值 **              ****val

**A **地址 ****           [0,1,2,3,4]


如果b=a进行拷贝时,其实复制的是a的引用地址,并不是对象里面的值

那么b复制的是a的指针,a和b都指向堆内存里的该指针的同一数据

 

而当我们a[0]=1时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也收了影响,这就是所谓的浅拷贝。

 

 

 

以借用JSON对象的parse和stringify方法实现深拷贝

 function deepClone(obj){

        var _obj=JSON.stringify(obj);

        var objClone=JSON.parse(_obj);

        return objClone;

    }

    var a=[1,2,3,4,5];

    var b=deepClone(a);

    a[0]="a";

    console.log(a,b)

 

数组的深拷贝方式有什么?至少找两种

// 用json的parse和stringify方法

function deepClone(obj){
    var _obj=JSON.stringify(obj);
    var objClone=JSON.parse(_obj);
    return objClone;
}
var a=[1,2,3,4,5];
var b=deepClone(a);
a[0]="a";
console.log(a,b)

// es6扩展运算符
var [...d]=a;
d[0]="es6扩展运算符";
console.log(a,d);

// concat 跟自己合并
var e=a.concat();
e[0]="concat 跟自己合并";
console.log(a,e)

// slice  截取方法
var f=a.slice(0);
f[0]="slice方法";
console.log(a,f)

// for循环实现
var arr2=copyArr(a);
function copyArr(a){
    let res=[];
    for(let i=0; i<a.length;i++){
         res.push(a[i])
    }
    return res
}
arr2[0]="for循环";
console.log(a,arr2)