js中的数组拷贝(浅拷贝,深拷贝)

作者: gavin 分类: uniapp,未分类 发布时间: 2022-02-18 11:41

今天写代码时需要拷贝一个内容会变化的数组,使用了=赋值,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();

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;
}