深拷贝与浅拷贝
假设B复制了A,当B变化时,如果A也变化,则为浅拷贝;如果A不变,则为深拷贝。
为什么使用深拷贝?
在改变新的数组或对象时,不会改变与数组或原对象
拷贝的要求程度:是仅深拷贝第一层级的对象属性或数组元素还是递归拷贝所有层级的对象属性和数组元素。
深浅拷贝只针对复杂数据类型来说
深拷贝:复制对象变量时,对于非基本类型的变量,则递归至基本类型变量之后,再进行复制。深拷贝后的对象与原来的对象是完全隔离的,互不影响。
浅拷贝:会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质上复制的是其引用,当引用指向的值改变时也会跟着改变。
一、浅拷贝:
可以使用Object.assign()、扩展运算符、slice()、concat()
数组:
法1:直接遍历(浅拷贝)
var arr=[1,2,3,4]; function copy(array){ var newArray=[]; for(var item of array){ newArray.push(item); } return newArray; } var copyArray=new copy(arr); copyArray[0]=100; console.log(arr);//[1, 2, 3, 4]
console.log(copyArray);//[100, 2, 3, 4]
法2:slice() ----------对于第一层级为深拷贝,第二层级以后为浅拷贝
var arr = [[1,[2,6,2]],2,3,4]; var newArr =arr.slice(0); newArr[1]=10; newArr[0][1][0]=100;//原数组的第二层级变化 console.log(arr);//[[1,[100,6,2]],2,3,4] console.log(newArr);//[[1,[100,6,2]],10,3,4]
法3:concat()-------对于第一层级为深拷贝,第二层级以后为浅拷贝
var arr=[1,2,3,4]; var copyArray=arr.concat(); copyArray[0]=100; console.log(arr);//[1, 2, 3, 4] console.log(copyArray);//[100, 2, 3, 4]
二、深拷贝:拷贝所有层级
1.不仅拷贝第一层级,还能够拷贝数组或对象所有层级的各项值
2. 不是单独针对数组或对象,而是能够通用于数组,对象和其他复杂的JSON形式的对象
法1:JSON.parse(JSON.stringify(arr));
var arr=[ {number:1}, {number:2}, {number:3} ]; var copyArray=JSON.parse(JSON.stringify(arr)); copyArray[0].number=100; console.log(arr);// [{number: 1}, { number: 2 }, { number: 3 }] console.log(copyArray);// [{number: 100}, { number: 2 }, { number: 3 }]
缺点:
它会抛弃对象的constructor,深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object,这种方法能正确处理的对象只有Number、String、Boolean、Array,也就是说,只有可以转成JSON格式的对象才可以这样用,向function没办法转成JSON;
法2:递归
var arr=[ {number:1}, {number:2}, {number:3} ]; function deepCopy(obj){ var newobj=Array.isArray(obj)?[]:{};//这里判断是对象还是数组是为了判断copy后的对象是数组还是对象 if(obj&&typeof obj==="object"){ for(let i in obj){ //如果obj的子元素是obj则递归复制,否则简单复制 newobj[i]=typeof(obj[i])=='object'?deepCopy(obj[i]):obj[i]; } } else{ return; } return newobj; } var copyArr=deepCopy(arr); copyArr[0].number=100; console.log(arr);// [{number: 1}, { number: 2 }, { number: 3 }] console.log(copyArr);// [{number: 100}, { number: 2 }, { number: 3 }]
法3:jQuery的extend()方法———默认是只对第一层级深拷贝,添加true可对所有层级深拷贝
var obj={ name:'123', score:{ english:80, math:90 } } var obj1=$.extend(true,{},obj); obj1.score.english=30; console.log(obj.score.english);//80 console.log(obj1.score.english);//30
法4:Object.assign()是深拷贝还是浅拷贝????对于第一级属性属于深拷贝,二级属性以后均为浅拷贝
var obj={ name:'123', score:{ english:80, math:90 } } var obj1=Object.assign({},obj); obj1.score.english=30; obj1.name='an'; console.log(obj);//{name: "123", score: {english:30,math:90}} console.log(obj1);//{name: "an", score: {english:30,math:90}}