问题
今天写代码时需要拷贝一个内容会变化的数组,使用了=赋值,slice(),concat()方法都不行,修改了原数组后拷贝数组也变了,原因是这个数组内容是object,而object是引用类型,需要使用深拷贝,最后使用var newArr = JSON.parse(JSON.stringify(arr));解决
浅拷贝&深拷贝
浅拷贝:如果数组元素是基本类型,就会拷贝一份,互不影响,而如果是对象或者数组,就会只拷贝对象和数组的引用,无论对新旧数组的哪一个进行了修改,两者都会发生变化。
深拷贝:完全的拷贝一个对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个。
var arr = [{name: 'wens'},{age: '26'}]; //原数组
var newArr1 = arr; //浅拷贝
var newArr2 = arr.slice(); //浅拷贝
var newArr3 = arr.concat(); //浅拷贝
var newArr4 = JSON.parse(JSON.stringify(arr)); //深拷贝
arr[0].name = 'leon';
arr[1].age = '27';
console.log(arr);
console.log(newArr1);
console.log(newArr2);
console.log(newArr3);
console.log(newArr4);
运行结果:
浅拷贝
1.使用=直接赋值
var newArr = arr;
缺点:由于数组是引用类型,修改了arr或者newArr中的一个会影响全部
2.使用slice()
var newArr = arr.slice();
3.使用concat()
var newArr = arr.concat();
slice()和concat()缺点:当数组内部属性值为引用对象时,使用slice和concat对对象数组的拷贝,整个拷贝还是浅拷贝,拷贝之后数组各个值的指针还是指向相同的存储地址。简单来说就是:
数组中的值如果是引用类型,对其进行增删改,会影响用slice复制的数组,
但是如果数组中的值是基本类型,就不会影响
深拷贝
1.使用JSON.stringify和JSON.parse
不仅可拷贝数组还能拷贝对象(但不能拷贝函数)
var newArr = JSON.parse(JSON.stringify(arr));
缺点:JSON.stringify()有一些局限,比如对于RegExp类型和Function类型则无法完全满足,而且不支持有循环引用的对象。
2.深拷贝的一个通用方法
实现思路:拷贝的时候判断属性值的类型,如果是对象,继续递归调用深拷贝函数
var deepCopy = function(obj) {
// 只拷贝对象
if (typeof obj !== 'object') return;
// 根据obj的类型判断是新建一个数组还是一个对象
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
// 遍历obj,并且判断是obj的属性才拷贝
if (obj.hasOwnProperty(key)) {
// 判断属性值的类型,如果是对象递归调用深拷贝
newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
}
}
return newObj;