文章目录
一、浅拷贝
浅拷贝和深拷贝都只针对于引用数据类型,浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存;
例如:
const obj_1 ={age:21}const obj_2 = obj_1;// 对象obj_2只复制了obj_1的地址
obj_2.age =19;
console.log(obj_1.age);// 输出:19
内存角度:对象obj_1会在栈中分配一个内存地址,该内存地址对应的值又会创建一个新的内存地址,该新的内存地址又指向堆这样一个数据结构,并在堆中创建对应的属性值age:21。而上述案例中创建obj_2并赋值obj_1,实际上只复制了指针,这么做将会导致obj_2与obj_1指向同一个地址,他们两从栈到堆这两种数据类型的链路都是一样的,obj_2修改属性age的值,导致obj_1中age的值发生改变,称作只实现了浅拷贝。
二、深拷贝
不同于浅拷贝,深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象;
三、判断深、浅拷贝
我们通过我们熟知的引用类型——数组,用其内置的一些方法判断是浅拷贝还是深拷贝
1.concat()方法
判断:
let list =['我爱','学习'];let copyList =[].concat(list);
copyList.push('JavaScript');
console.log(list);// ['我爱', '学习']
console.log(copyList);// ['我爱', '学习', 'JavaScript']
我们使用concat()方法拷贝副本,返回新构建的数组,此时我对新数组元素的添加也不会影响到原数组,然而。。。答案为:浅拷贝
2.slice()方法
判断:
let list =['我爱','学习'];let copyList = list.slice();
copyList.push('JavaScript');
console.log(list);// ['我爱', '学习']
console.log(copyList);// ['我爱', '学习', 'JavaScript']
我们使用slice()方法不传参的方式从头到尾拷贝副本,并且返回新数组,即使我对新数组添加元素也不会影响到原数组,然而。。。答案仍然为:浅拷贝
3.Array.from()方法
判断:
let list =['我爱','学习'];let copyList = Array.from(list);
copyList.push('JavaScript');
console.log(list);// ['我爱', '学习']
console.log(copyList);// ['我爱', '学习', 'JavaScript']
我们使用ES6中Array.from()方法同样以不影响原数组的方式实现了拷贝,然而。。。答案依旧为:浅拷贝
4.扩展运算符
判断:
let list =['我爱','学习'];let copyList =[...list];
copyList.push('JavaScript');
console.log(list);// ['我爱', '学习']
console.log(copyList);// ['我爱', '学习', 'JavaScript']
我们再次使用ES6中扩展运算符,同理:浅拷贝
我们来考证一下:
let list =[{name:'Tom'}];let copyList =[...list];
copyList[0].name ='Jerry'
console.log(list[0].name);// Jerry
console.log(copyList[0].name);// Jerry
我们将数组元素都换成引用类型,执行以上方法,并通过拷贝副本改变数组元素的值,我们会发现原数组的元素也发生了改变,由此可见,确实是浅拷贝。除此之外,数组的其他方法如map()、filter()、reduce(),都是会造成浅拷贝的。
四、实现浅拷贝
1.Object.assign方法
let list ={obj:{hobby:'JavaScript'}}let copyList = Object.assign({}, list);
copyList.obj.hobby ='Vue'
console.log(list.obj.hobby);// Vue
2.for in方法
let user1 ={name:"小明",age:30,height:1.9,hobby:{project:'React'}};let user2 ={};for(let i in user1){
user2[i]= user1[i];//user1[i]输出的是每一个属性的值,将user1的每一个属性的值取出来赋值给user2对象}
user2.name ='小蓝'
user2.hobby.project ='Vue'
console.log(user1)//{ name: "小明", age: 30, height: 1.9, hobby: { project: 'Vue' } }
五、实现深拷贝
1.递归实现
采用递归去拷贝所有层级属性
functiondeepClone(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, b)// [2,2,3,4] [1,2,3,4]
2.JSON.stringify与JSON.parse
通过JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成一个全的新的对象;
let list =[{name:'Tom'}];let copyList =JSON.parse(JSON.stringify([...list]));
copyList[0].name ='Jerry'
console.log(list[0].name);// Tom
console.log(copyList[0].name);// Jerry
3.loadash函数库
函数库lodash,也有提供_.cloneDeep用来做深拷贝
let lodash =require('lodash');let list =[{name:'Tom'}];let copyList = lodash.cloneDeep(list);
copyList[0].name ='Jerry'
console.log(list[0].name);// Tom
console.log(copyList[0].name);// Jerry
版权归原作者 JV_32 所有, 如有侵权,请联系我们删除。