深拷贝和浅拷贝,顾名思义就是对拷贝出来的数据有深浅之分,其实深浅拷贝只是对对象而言,因为在js的存储中,存储数据的方式有两种,栈内存和堆内存。
1、原始数据类型直接存储在栈中,占据空间小、大小比较稳定,属于被频繁使用数据,所以放入栈中存储;
2、引用数据类型存储在堆中,占据空间大、大小不固定 在栈内存中只是存了一个地址来表示对堆内存中的引用。
浅拷贝
定义
对于基本数据类型的成员变量,浅拷贝直接进行值传递,也就是将属性值复制了一份给新的成员变量;
对于引用数据类型的成员变量,比如成员变量是数组、某个类的对象等,浅拷贝就是引用的传递,也就是将成员变量的引用(内存地址)复制了一份给新的成员变量,他们指向的是同一个事例。在一个对象修改成员变量的值,会影响到另一个对象中成员变量的值。
用法
一、直接赋值
将旧对象的变量名直接赋值给新的对象变量,那么旧对象的属性值一改变,新对象也会改,因为只拷贝了内存地址
二、调用Object.assign()
该方法第一个参数是新对象,第二个参数是旧对象,旧对象中的属性值如果也是对象,那么新对象只是拷贝了内存地址
三、…对象扩展运算符
运用扩展运算符将旧对象在一个新的空对象中展开,如果旧对象中的属性值是对象,那么新对象也是浅拷贝而已
四、for循环遍历对象,将旧对象的属性值依次赋值给新对象,如果旧对象中属性值是一个对象,也只是浅拷贝
深拷贝
定义
对于基本数据类型,深拷贝复制所有基本数据类型的成员变量的值;
对于引用数据类型的成员变量,深拷贝申请新的存储空间,并复制该引用对象所引用的对象,也就是将整个对象复制下来。所以在一个对象修改成员变量的值,不会影响到另一个对象成员变量的值。
用法
一、通过递归的方式实现深拷贝
function deepCopy(data){
var _data; // 初始化结果,因为结果可能为js任意类型,所以没有赋值.
// 1. 先验证data是什么类型的数据
// 如果是基本数据类型,那么直接赋值_data
if(!(data instanceof Object)){ // 如果是基本数据类型
_data = data // 直接赋值
return _data /// 输出赋值结果,结束下面语句
}
if(Array.isArray(data)){ // 验证是不是数组 如果是数组 则进行if语句里面赋值空数组,不是的话直接进行下次判断.
_data = [] // 对_data赋值空数组
}
// 验证data是否为对象,如果是对象 则进行if语句里面赋值空对象,不是的话直接进行下次判断.
if(data.constructor === Object){
_data = {} // 对_data赋值为空对象
}
// 2. 将data中内容添加到 _data中
for(var i in data){
// 如果 data[i] 是数组或者对象,则需要进一步深拷贝,所以再次执行deepCopy
// 将deepCopy() 的返回值 赋值给_data
_data[i] = deepCopy(data[i])
}
return _data
}
二、使用JSON.stringify和JSON.parse
用JSON.stringify(obj)把对象转换成字符串,再用JSON.parse(obj)把字符串转换成新的对象
三、使用函数库lodash的_.cloneDeep()
四、通过JQuery的extend方法实现深拷贝