拷贝,理解为复制的意思,拷贝就是复制已经存在的一个变量给另外一个变量,如:var a = 10; var b = a; b拷贝了a。那么 a 等不等于 b 呢?要搞明白我们得先来了解下JavaScript的内存管理机制。
JavaScript的内存管理机制
内存的周期是: 分配 -> 使用 -> 释放
1. 分配:
变量被定义时候分配内存,内存存放又分为栈、堆、地址池。其中栈存放变量,且有固定的大小(基础数据),堆存放复杂对象(引用数据类型),池存放常量。
注意:JS不允许直接访问堆内存中的位置,因此我们不能直接操作对象的堆内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。因此,引用类型的值都是按引用访问的。这里的引用,我们可以粗浅地理解为保存在栈内存中的一个地址,该地址与堆内存的实际值相关联。
2. 使用:
对分配内存进行读取与写入的操作。如: var a = 1;a = 2; // 写入内存
3. 释放:
所分配的内存确实已经不再需要了,释放这过程涉及了垃圾回收机制,Javascript内嵌了垃圾收集器,用来跟踪内存的分配和使用,以便当分配的内存不再使用时,自动释放它(如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收)。垃圾收集器会按照固定的时间间隔,或代码执行中预定的收集时间,周期性地执行这一操作。如下:
function fun1(){ var obj = {name:'ja'};} var f1 = fun1(); obj 会被回收,因为var obj使用完
function fun2(){var obj = {name:'va'};return obj;}var f2 = fun2(); obj 不会被回收,因为被f2引用,f2属于全局变量,页面没有卸载的情况下是不会被回收的
JavaScript的浅拷贝和深拷贝
基本数据类型不存在浅深拷贝问题,引用类型存在
1. 浅拷贝:浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存,修改对象,原对象也会改变。方法:Object.assign()(当object只有一层的时候,是深拷贝)、Array.prototype.concat()、Array.prototype.slice()
2. 深拷贝:深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。方法:JSON.parse(JSON.stringify())(但不能处理函数、underfined)、遍历对象(只有一层对象直接循环,两层对象则需要判断类型)、递归(多层对象)
浅拷贝:
深拷贝:
递归拷贝:
var p = { "id":"007","name":"刘德华","wife":{"id":"008","name":"刘德的妻子","address":{"city":"北京","area":"海淀区"}}}
//写函数
function copyObj(obj){let newObj={};for(let key in obj){if(typeof obj[key] =='object'){//如:key是wife,引用类型,那就递归newObj[key] = copyObj(obj[key])}else{//基本类型,直接赋值newObj[key] = obj[key];}}return newObj;}
let pNew = copyObj(p);pNew.wife.name="张三疯";pNew.wife.address.city = "香港";console.log(pNew);console.log(p);