js浅拷贝和深拷贝
vue开发过程中,由于常常与数据打交道,弄懂每个data的状态是很有必要的。如果数据耦合度较高,弄懂浅拷贝和深拷贝就显得尤为重要。因此在此总结一下。
1.对于基本数据类型,由于变量名和值都存在栈内存中,因此,简单的=会开辟一个新空间,赋值和被复制的变量都是相互独立的:
let a = "aaa"; let b; b = a; b = "bbb"; // 这里输出bbb console.log(b);
结果如下:
2.接下来我们讨论较为复杂的object类型的数据。由于引用数据类型名字存在栈内存中,值存在堆内存中,栈内存会提供一个引用的地址指向堆内存中的值。当我们用=进行赋值时,其实只是复制了引用地址,如果这时改变值,会影响到赋值与被复制的双方:
浅拷贝可以用=赋值或者 Object.assign方法,这里重点说下深拷贝方法
深拷贝实现方法:
(1)for···in 循环到第一层:
var obj1 = { a: "aaa", b: "bbb", c: { d: "ddd", }, }; obj2 = {}; for (let i in obj1) { obj2[i] = obj1[i]; } obj2.a = "aaa2"; obj2.c.d = "ddd2"; console.log(obj1); console.log(obj2);
结果如下:
发现只有a改变了,c并没有改变,不算是真正的深拷贝,但我们这里有个思路:递归实现不就行了
function deepClone(obj){ // 考虑到objClone变量的多样性 let objClone = Array.isArray(obj)?[]:{}; if(obj && typeof obj==="object"){ for(key in obj){ if(obj.hasOwnProperty(key)){ //判断obj子元素是否为对象,如果是,递归复制 if(obj[key]&&typeof obj[key] ==="object"){ objClone[key] = deepClone(obj[key]); }else{ //如果不是,简单复制 objClone[key] = obj[key]; } } } } return objClone; } let a={ a: "aaa", b: "bbb", c: { d: "ddd", }, }; b=deepClone(a); a.a="aaa2"; a.c.d="ddd2" console.log(a); console.log(b);
结果如下:
发现不论多少层都能实现a和b互不干扰。
(2)此外,我们还可以通过loadash库实现深拷贝:
let result = _.cloneDeep(test)
(3)通过JSON对象来实现深拷贝,这个方法比较取巧,且不依赖其他库,在我编程中用的最多:
function deepClone(obj) { var temp_obj = JSON.stringify(obj), objClone = JSON.parse(temp_obj); return objClone; }
对于数组,我们可以用slice和concat实现数组的深拷贝:
// 当数组里面的值是基本数据类型,比如String,Number,Boolean时,属于深拷贝 // 当数组里面的值是引用数据类型,比如Object,Array时,属于浅拷贝 var arr1 = ["1","2","3"]; var arr2 = arr1.slice(0); arr2[1] = "9"; console.log("数组的原始值:" + arr1 ); console.log("数组的新值:" + arr2 );
// 当数组里面的值是基本数据类型,比如String,Number,Boolean时,属于深拷贝 var arr1 = ["1","2","3"]; var arr2 = arr1.concat(); arr2[1] = "9"; console.log("数组的原始值:" + arr1 ); console.log("数组的新值:" + arr2 ); // 当数组里面的值是引用数据类型,比如Object,Array时,属于浅拷贝 var arr1 = [{a:1},{b:2},{c:3}]; var arr2 = arr1.concat(); arr2[0].a = "9"; console.log("数组的原始值:" + arr1[0].a ); // 数组的原始值:9 console.log("数组的新值:" + arr2[0].a ); // 数组的新值:9
以上就是常用的拷贝技巧,希望对大家有所帮助。
愿所有远方终将抵达
愿爱你的人一直都在