深拷贝和浅拷贝最根本的区别在于是否是真正获取了一个对象的复制实体,而不是引用,
1)深拷贝在计算机中开辟了一块内存地址用于存放复制的对象,
2)而浅拷贝仅仅是指向被复制的内存地址,如果原地址中对象被改变了,那么浅复制出来的对象也会相应改变。
1 2 3 4 5 6 7 8 9 10 11 |
//深拷贝 var a=123; var b=a; a=456; console.log(b) //123 //浅拷贝 var obj1={name:123}; var obj2=obj1; obj1.name=456; console.log(obj2.name) //456 |
这是个极其简单的例子,深浅拷贝一个最大的表征就是,使用的变量是否受到它原始变量的影响(这个说法不官方哈)
另外,js有以下两种数据类型:
基本类型:Number Boolean String undefined null
引用类型:Object Function
有人说,基本数据类型复制都是深拷贝,引用类型都是浅拷贝,这个说法还是有问题的,后半句不全面,比如:
1 2 3 4 5 6 7 8 9 10 11 12 |
var arr=[1,2,3]; function test1(arr) { arr[0]=9; console.log(arr) } function test2(arr) { arr=[9,0]; console.log(arr) } test1(arr); // 9 2 3 test2(arr); // 9 0 console.log(arr) // 9 2 3 |
test1去改变引用的值,test2去赋值。
拷贝有很多的业务场景,算是一种复用,网上也有很多介绍,就不多说了,我个人理解的他们在应用场景上的不同,主要是看业务中对你拷贝的数据的可操作性,如果只是一种展示,那么浅拷贝就行,如果有后续的修改或删除,那就要深拷贝了。
下面就针对两种引用类型的深拷贝进行说明
数组
1、通过 Array.from
1 2 3 4 |
var arr1=[1,2,3]; var arr2=Array.from(arr1); arr1.push(4); console.log(arr2) // 1 2 3 |
2、通过 ES6 的解构赋值
1 2 3 4 5 6 7 8 9 10 11 |
var arr1=[1,2,3]; var arr2=[...arr1]; arr1.push(4); console.log(arr2); // 1 2 3 // 或者: function show(...arr1){ //直接来复制arguments这个伪数组,让它变成真正的数组,从而拥有数组的方法。 alert(arr1); //1234 arr1.push(5); alert(arr1); //12345 } show(1,2,3,4) |
3、通过 concat
1 2 3 4 |
var arr1=[1,2,3]; var arr2=arr1.concat([]); arr1.push(4); console.log(arr2); // 1 2 3 |
4、通过splice
1 2 3 4 5 |
var arr1=[1,2,3]; var arr2=arr1.splice(0); arr1.push(4); console.log(arr2); // 1 2 3 //这种写法影响到了arr1,所以慎用 |
5、map,可以返回数组的遍历
1 2 3 4 |
var arr1=[1,2,3]; var arr2=arr1.map(item=>item); arr1.push(4); console.log(arr2); // 1 2 3 |
6、split、join
1 2 3 4 5 |
var arr1=[1,2,3]; var arr2=arr1.join('-').split('-'); arr1.push(4); console.log(arr2); // 1 2 3 //如果arr1的元素是数字,arr2中现在都是字符串了,使用的时候注意 |
7、小算法
1 2 3 4 5 6 7 |
var arr1=[1,2,3,4]; var arr2=[]; for(var i=0; i<arr1.length; i++){ arr2[i]=arr1[i]; } arr1.push(5); alert(arr2); //1234 |
对象
1、JSON-api
1 2 |
var _obj = JSON.stringify(obj), objClone = JSON.parse(_obj); |
2、Object.assign()拷贝
1 2 3 |
var obj={name:123}, objClone={}; Object.assign(objClone,obj); |
3、递归算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
//使用递归的方式实现数组、对象的深拷贝 function deepClone1(obj) { //判断拷贝的要进行深拷贝的是数组还是对象,是数组的话进行数组拷贝,对象的话进行对象拷贝 var objClone = Array.isArray(obj) ? [] : {}; //进行深拷贝的不能为空,并且是对象或者是 if (obj && typeof obj === "object") { for (key in obj) { if (obj.hasOwnProperty(key)) { if (obj[key] && typeof obj[key] === "object") { objClone[key] = deepClone1(obj[key]); } else { objClone[key] = obj[key]; } } } } return objClone; } //这里可能牵扯到一个所谓循环引用的问题,可以做一个对象数组,如果已经存在过,就直接赋值,不再进行回调 |
4、jQuery的extend
1 2 |
var array = [1,2,3,4]; var newArray = $.extend(true,[],array); |
5、lodash函数库实现深拷贝
lodash很热门的函数库,提供了 lodash.cloneDeep()实现深拷贝
先总结这些吧,如果以后发现更多方法再回来更新~
参考:
https://segmentfault.com/a/1190000012828382
https://www.jianshu.com/p/0d7bd31ccf43