“携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天juejin.cn/post/712312…
拷贝对象(也是个面试题)
对象的深拷贝和浅拷贝的区别如下:
浅拷贝:仅仅复制对象的引用(引用指的是指针),而不是对象本身
深拷贝:采用递归的方式把复制的对象所引用的全部对象都复制一遍(包括子对象)
递归可以理解为是读取数据的一种方式
所有的赋值运算对于对象来说都是浅拷贝 b=a相当于把指针拷贝给了b
Js中的堆内存和占内存(涉及的基本都是对象的拷贝)
在js引擎中对变量的存储主要有两种位置,堆内存和栈内存。
在java中对内存的处理类似,栈内存主要用于存储各种基本类型的变量(已知大小),包括Boolean、Number、String、Undefined、Null,以及对象变量的指针,这是栈内存给人的感觉就像是一个线性排列的空间,每个小单元大小基本相等。
而堆内存主要负责对象Object这种变量类型的存储(未知大小,因为对象中有很多不确定的数据,后期可能还会修改它)
一般来说栈内存线性有序存储,容量小,系统分配效率高。而堆内存首先要在堆内存新分配存储区域,之后又要把指针存储到栈内存中。效率相对就要低一些了。垃圾回收方面,栈内存变量基本上用完就回收了,而堆内存中的变量因为存在很多不确定的引用,只有当所有调用的变量全部销毁之后才能回收。
堆内存是无序的
引用数据类型指的就是对象
直接=赋值时浅拷贝
基本类型——名值存储在栈内存中,例如let a=1;
| 栈内存 | |
|---|---|
| Name | Val |
| a | 1 |
当你b=a复制时,栈内存会新开辟一个内存,例如下面这样
| 栈内存 | |
|---|---|
| Name | Val |
| a | 1 |
| b | 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)