深拷贝和浅拷贝
区别:浅拷贝只是增加一个指针指向已存在的内存地址,仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅拷贝出来的对象也会相应的改变。深拷贝是增加了一个指针并且申请了一个新的内存,使这个指针指向这个新的内存。
简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,如果B没变,那就是深拷贝。
1.如果是基本数据类型,名字和值都会存储在栈内存中。
var a = 1; b = a; // 栈内存会开辟一个新的内存空间,此时b和a都是相互独立的 b = 2; console.log(a); // 1 //当然,这也算不上深拷贝,因为深拷贝本身只针对较为复杂的object类型数据。
2.如果是引用数据类型,名字存在栈内存中,值存在堆内存中,但是栈内存会提供一个引用地址指向堆内存中的值。比如浅拷贝
let a = [1,2,3]; b = a; b[0] = 4; console.log(b); //[4, 2, 3] console.log(a); //[4, 2, 3]
当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值。
那,要是在堆内存中也开辟一个新的内存专门为b存放值,就像基本类型那样,岂不就达到深拷贝的效果了。
3.实现浅拷贝的方法
(1)直接用=赋值
let a=[0,1,2,3,4],b=a; console.log(a===b); a[0]=1; console.log(b); //[1, 1, 2, 3, 4] console.log(a); //[1, 1, 2, 3, 4]
(2)Object.assign()方法
var obj = { a: 1, b: 2 } var obj1 = Object.assign(obj); obj1.a = 3; console.log(obj.a) // 3
(3)for...in只循环第一层
// 只复制第一层的浅拷贝 function simpleCopy(obj1) { var obj2 = Array.isArray(obj1) ? [] : {}; for (let i in obj1) { obj2[i] = obj1[i]; } return obj2; } var obj1 = { a: 1, b: 2, c: { d: 3 } } var obj2 = simpleCopy(obj1); obj2.a = 3; obj2.c.d = 4; alert(obj1.a); // 1 alert(obj2.a); // 3 alert(obj1.c.d); // 4 alert(obj2.c.d); // 4
4.实现深拷贝的方法
(1)通过JSON.parse(JSON.stringify())对象来实现深拷贝。
弊端: 无法实现对对象中方法的深拷贝,如果obj里有函数或者undefined,则序列化的结果会把函数或 undefined丢失;
let a = [{name:'cd',age:9},{name:'as',age:12}]; b = JSON.parse(JSON.stringify(a)); b[0].name = 'qq'; console.log(a); //[{name:'cd',age:9},{name:'as',age:12}] console.log(b); //[{name:'qq',age:9},{name:'as',age:12}]
const test = { name: 'a', date: function hehe() { console.log('fff') }, }; const copyed = JSON.parse(JSON.stringify(test)); test.name = 'test' console.error(test, copyed)
(2)通过jQuery的extend方法实现深拷贝。
var array = [1,2,3,4]; var newArray = $.extend(true,[],array);// true为深拷贝,false为浅拷贝 newArray[0]=9; console.log(newArray); //[9, 2, 3, 4] console.log(array); //[1, 2, 3, 4]
(3)采用递归去拷贝所有层级属性。
function deepClone(obj){ let objClone = Array.isArray(obj)?[]:{}; if(obj && typeof obj==="object"){ for(key in obj){ if(obj.hasOwnProperty(key)){ //判断ojb子元素是否为对象,如果是,递归复制 if(obj[key]&&typeof obj[key] ==="object"){ objClone[key] = deepClone(obj[key]); }else{ //如果不是,简单复制 objClone[key] = obj[key]; } } } } return objClone; } let a=[1,2,3,4],b=deepClone(a); a[0]=2; console.log(a); //[2, 2, 3, 4] console.log(b); //[1, 2, 3, 4]
(4)使用扩展运算符实现深拷贝。
// 当value是基本数据类型,比如String,Number,Boolean时,是可以使用拓展运算符进行深拷贝的 // 当value是引用类型的值,比如Object,Array,引用类型进行深拷贝也只是拷贝了引用地址,所以属于浅拷贝 var car = {brand: "BMW", price: "380000", length: "5米"} var car1 = { ...car, price: "500000" } console.log(car1); // { brand: "BMW", price: "500000", length: "5米" } console.log(car); // { brand: "BMW", price: "380000", length: "5米" }
(5)如果对象的value是基本类型的话,也可以用Object.assign来实现深拷贝,但是要把它赋值给一个空对象。
var obj = { a: 1, b: 2 } var obj1 = Object.assign({}, obj); // obj赋值给一个空{} obj1.a = 3; console.log(obj.a); // 1
(6)lodash函数库实现深拷贝。https://blog.csdn.net/ccf19881030/article/details/105452586
let a = [{name:'cd',age:9},{name:'as',age:12}]; let b = _.cloneDeep(a); b[0].name = 'qq'; console.log(a); console.log(b);
(7)手动实现深拷贝。
let obj1 = { a: 1, b: 2 } let obj2 = { a: obj1.a, b: obj1.b } obj2.a = 3; alert(obj1.a); // 1 alert(obj2.a); // 3