详解深拷贝和浅拷贝以及如何深拷贝

JS 同时被 2 个专栏收录
32 篇文章 0 订阅
6 篇文章 0 订阅

一、如何区分深拷贝和浅拷贝

  • 内在的区别:浅拷贝就是简单的把指向别人的值的一个指针给复制过来,深拷贝就是实实在在的把别人的值给复制过来。
  • 直接显示出来的区别:浅拷贝就是双方不是独立的,还会互相影响;深拷贝是不会影响到彼此,是独立的个体。

深拷贝与浅拷贝的存在主要还是受拷贝的数据类型所影响的。当拷贝的是js基本数据类型时,都会是深拷贝;如果拷贝的是js引用数据类型时,简单的赋值过来的时候就是浅拷贝,需要做一些特殊处理让它变成深拷贝。

如果不理解上面所说的就需要先好好理解下什么是基本数据类型,什么是引用数据类型,可以先看看下面这篇博客https://blog.csdn.net/Sunday97/article/details/84869727

二、举例加深理解深拷贝和浅拷贝

首先了解下js的数据类型:

  • js的六大数据类型:Number, String, Boolean, Undefined , Null , Object
  • 基本数据类型:Number,String,Boolean,Undefined, Null
  • 引用数据类型:Object , Array, Function
//当拷贝的是基本数据类型时
var a = 1;
var b = a;
a = 2;
console.log(a,b);//2 1

//当拷贝的是引用数据类型时
var a = [1,2,3];
var b = a;
a[0] = 2;
console.log(a,b);//[2,2,3] [2,2,3]

三、图文理解

基本类型的值存储在栈内存中,引用类型的值存储在堆内存中。
如果不理解栈内存和堆内存,可以先看下面这篇文章:
https://blog.csdn.net/Sunday97/article/details/108485921

  • 当b拷贝a,a是基本类型的值时,给a与b分配的是独立的空间,互不影响

在这里插入图片描述

  • 当b拷贝a,a是引用类型的值时,b拷贝过来的是一个指针,这个指针指向a的值。当改变a的值时,改变的是堆内存中的值,栈内存中的指针指向并没有改变,都指向的是同一个值,所以改变某个变量的值时,对另一个复制了它的变量也会产生影响。
    在这里插入图片描述

四、哪些方法是浅拷贝,如何进行深拷贝

1、浅拷贝

浅拷贝可以简单理解为,发生在栈中的拷贝行为,只能拷贝基本值和引用值的地址。

  • ES6 定义了 Object.assign() 方法来实现浅拷贝。
	let a = {
	    name:"huangQian",
	    like:{
	       fruit:"apple",
	       color:"white"
	    }
	}
	let b = Object.assign({},a);
	console.log(a,b)

在这里插入图片描述
会发现拷贝过来了,a和b一模一样。

现在对a进行更改,看看b的变化:

let a = {
	    name:"huangQian",
	    like:{
	       fruit:"apple",
	       color:"white"
	    }
	}
	let b = Object.assign({},a);
	a.name = "nicole";
	a.like.color = "black";
	console.log(a,b)

在这里插入图片描述
会发现b中属于基本数据类型的name属性的值没有发生改变,但是属于引用数据类型的like里面的数值发生了和a一样的变化,因为指向了同一个地址。

  • 数组的slice()concat() 方法也属于浅拷贝
let a = [1,2,[3,4]];
let b = a.slice(0);
console.log(a,b);//[1,2,[3,4]]  [1,2,[3,4]]

a[0] = 2;
a[2][0] = 4;
console.log(a,b)//[2,2,[4,4]]  [1,2,[4,4]]

2、深拷贝

深拷贝可以简单理解为,同时发生在栈中和堆中的拷贝行为,除了拷贝基本值和引用值的地址之外,地址指向的堆中的对象也会发生拷贝。

  • JSON.stringify() 可以间接实现深拷贝

将需要深拷贝的对象序列化为一个 JSON 字符串,然后根据这个字符串解析出一个结构和值完全一样的新对象

let a = {
	    name:"huangQian",
	    like:{
	       fruit:"apple",
	       color:"white"
	    }
	}
let b = JSON.parse(JSON.stringify(a));
console.log(a,b);

在这里插入图片描述

let a = {
	    name:"huangQian",
	    like:{
	       fruit:"apple",
	       color:"white"
	    }
	}
let b = JSON.parse(JSON.stringify(a));
a.name = "nicole";
a.like.color = "black";
console.log(a,b);

在这里插入图片描述
会发现改变a的值,不会对b产生任何影响

⚠️这种方法需要保证对象是安全的,例如属性值不能是 undefined、symbol、函数、日期和正则。

  • 使用 $.extend() 方法实现深拷贝

$.extend() 方法属于 jquery 的方法。这个方法实现深拷贝的基本思路是:如果是基本值或除了对象或数组之外的引用值,直接赋值;如果是对象或数组就需要进行递归,直到递归到基本值或除了对象或数组之外的引用值为止。

用原生js来表达它的思路就可以写成如下代码:

function deepCopy(originObj) {
    var resultObj = Array.isArray(originObj)?[]:{};
    for(var key in originObj) {
       var isObj = Object.prototype.toString.call(originObj[key]) ===[object Object];//是否是对象
       if(isObj || Array.isArray(originObj[key])) //如果是对象或者数组,再走一遍函数
       {
           deepCopy(originObj[key]);
       } else {
           resultObj[key] = originObj[key]
       }
    }
    return resultObj;
}
  • 0
    点赞
  • 0
    评论
  • 2
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 创作都市 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值