数组、对象的深拷贝跟浅拷贝

前言

浅拷贝对指针的拷贝,拷贝后两个指针指向同一个内存空间,改变一个数组会同时改变另一个数组。

深拷贝对指针和指针指向的内容都进行拷贝,深拷贝后的两个数组完全独立,存储在不同的地址。

 

1.对象的浅拷贝

1、对象的直接遍历赋值。

2、ES6中的 var copyObj = Object.assign({}, obj);

3、ES7扩展运算符 var copyObj = { ...obj }

Object.assign()是深拷贝还是浅拷贝?

Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

Object.assign()拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。也就是说,如果对象的属性值为简单类型(如string, number),通过Object.assign({},srcObj);得到的新对象为深拷贝;如果属性值为对象或其它引用类型,那对于这个对象而言其实是浅拷贝的。

2、对象的深拷贝

1.用 JSON.stringify 把对象转换成字符串,再用 JSON.parse 把字符串转换成新的对象 JSON.parse(JSON.stringify(Obj))

但是需要注意的是
可以转成 JSON 格式的对象才能使用这种方法,如果对象中包含 function 或 RegExp 这些就不能用这种方法了。

2.Object.assign()拷贝

当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。

3、数组的浅拷贝

(两者指向不同的对象,但是只能拷贝一层)

  • array.concat();
  • array.slice(0);

如果该元素是个对象引用 (不是实际的对象),slice 会拷贝这个对象引用到新的数组里。两个对象引用都引用了同一个对象。如果被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变,所以是浅拷贝。

对于字符串、数字及布尔值来说(不是 String、Number 或者 Boolean 对象),slice 会拷贝这些值到新的数组里。在别的数组里修改这些字符串或数字或是布尔值,将不会影响另一个数组。

也就是说,如果原数组改变的是基本数据类型,比如String,Boolean,Number的数据,不会影响到新数组;
但是如果改变的是对象或者数组中的数据,是会影响到新数组的,也也就是对于对象或者数组,新旧数组指向的是一个对象。

4、数组的深拷贝

(下面说的深拷贝是基本对象的深拷贝,不考虑对象的复杂属性,比如set,get,Function等)

1、最简单的方式 JSON.parse(JSON.stringify(Obj)) 这种方法使用较为简单,可以满足基本的深拷贝需求,而且能够处理JSON格式能表示的所有数据类型,但是对于正则表达式类型、函数类型等无法进行深拷贝(而且会直接丢失相应的值)。

 

具体看下面的例子

//深拷贝
var arr1 = [1, 2, 3];
var arr2 = arr1.slice();
arr1.push(4);
console.log(arr2)      //[1, 2, 3]
//浅拷贝
var arr1 = [{a:1}];
var arr2 = arr1.slice();
arr1[0].a = 2;
console.log(arr2[0].a)          //2

同样的方法,一会是深拷贝一会是浅拷贝,对数组来说,深拷贝和浅拷贝得看数组的格式吗?

回答:

这就要分 基本数据类型和引用数据类型Number  String  Boolean  Null和Undefined属于基本数据类型,基本数据类型是按值访问的,直接等号赋值是值复制Object Array Function Data等 属于引用数据类型,引用数据类型只能操作对象在栈内存中的引用地址,等号赋值是引用赋值你第一个 截取的是 1  2  3这三个数字返回数组,因为数字是基本数据类型 所以直接是值复制第第二个 截取的是 {a:1}这个对象,对象是引用数据类型,复制的是引用地址,使arr1和arr2指向同一引用地址,所以更改arr1,arr2也会变化

解决方法

1、用传统的循环赋值

 简单写法

let one_brand = [
    {name: 'A', count: 1, value: Infinity},
    {name: 'B', count: 2},
]

// 深拷贝
// 方法一
let two_brand = one_brand.map(o => Object.assign({}, o));
// 方法二
let two_brand = one_brand.map(o => ({...o}));

 

2、还有一个方法就是简单粗暴法!原理很简单,就是先把对象转成字符串,再把字符串转成对象!(这种方法只编码 JSON 支持的值,但是前端处理中,基本都是满足)

 

 

最终得出结果

不管是数组还是对象想要实现深拷贝,可以直接用JSON.parse(JSON.stringify(data))来进行深拷贝

posted @ 2020-11-23 16:28  心向阳  阅读(308)  评论(0编辑  收藏  举报