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


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

问题

要拷贝一个内容会变化的数组,使用了=赋值,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);

 

运行结果: 

>Array [object { name:"leon"},Object { age:"27"}]
>Array [Object { name:"leon"},Object { age:"27"}]
>Array [Object { name:"leon"},Object { age:"27"}]
>Array [Object { name:"leon"},Object { age:"27"}]
>Array [Object { name:"wens"},Object { age:"26"}]

浅拷贝

1.使用=直接赋值

var newArr = arr;

缺点:由于数组是引用类型,修改了arr或者newArr中的一个会影响全部

2.使用slice()

var newArr = arr.slice();

3.使用concat()

var newArr = arr.concat();

slice()和concat()缺点:当数组内部属性值为引用对象时,使用slice和concat对对象数组的拷贝,整个拷贝还是浅拷贝,拷贝之后数组各个值的指针还是指向相同的存储地址。简单来说就是:

数组中的值如果是引用类型,对其进行增删改,会影响用slice复制的数组,
但是如果数组中的值是基本类型,就不会影响

 

JSON.stringify()将值转换为相应的JSON格式:

  • 转换值如果有toJSON()方法,该方法定义什么值将被序列化。
  • 非数组对象的属性不能保证以特定的顺序出现在序列化后的字符串中。
  • 布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值。
  • undefined、任意的函数以及symbol值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成null(出现在数组中时)。函数、undefined被单独转换时,会返回undefined,如JSoN.stringify(function(){})or JSON.stringify(undefined)。
  • 对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误。
  • 所有以symbol 为属性键的属性都会被完全忽略掉,即便replacer参数中强制指定包含了它们。
  • Date日期调用了toJSON()将其转换为了string字符串(同Date.tolsOString()),因此会被当做字符串处理。
  • NaN和Infinity格式的数值及nul都会被当做null。
  • 其他类型的对象,包括Map/Set/weakMap/weakSet,仅会序列化可枚举的属性。

深拷贝

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

 

转载:js中的数组拷贝(浅拷贝,深拷贝)_王俊

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM