深拷贝和浅拷贝详解和里面坑的说明

背景:

本人一直都习惯使用JSON和...解构赋值进行深拷贝,但其实他们都有对应的缺点我猜很多人都不一定知道特别是一些刚入行没多久的前端开发,所以想写个文章标明给大家方便在合适的场景选择合适的方式,如果只是想看深拷贝方式或者他们的坑可以直接划到中间观看。

什么是深拷贝什么是浅拷贝?:

深拷贝 :将对象从内存中完整的拷贝一份出来,在堆中开辟一片新的区域存放新对象。 浅拷贝:创建一个新对象,这个对象有原始对象的一份精确拷贝,如果拷贝的是基本数据类型,拷贝的就是基本数据类型的值;如果拷贝的是内存地址,拷贝的就是它的引用。

区别:

深拷贝修改新对象不会影响原对象,它们之间互不影响;浅拷贝基本数据类型之间互不影响,引用数据类型其中一个改变了内存地址,就会影响另一个对象。

举例说明:

基本数据类型: String、Number、boolean、null、undefined,基本数据类型值放在栈区,可直接访问与修改,且相互之间不会影响
引用类型:引用类型地址放在栈区,值放在堆区,所以当你进行赋值操作,其实赋值的是地址,所以二者之间是有关系的:

ini 复制代码
var obj1={
   name:'我是初始值',
   age:18
};
var obj2 = obj1;
obj2.name = 'meimei';

console.log(obj1);//{name:'meimei',age:18}
console.log(obj2);//{name:'meimei',age:18}

上面是浅拷贝例子,可以看出来,直接使用=其实就是浅拷贝,赋值的是地址,所以改变obj2时,obj1也会被改变; 所以我们要开一个新的空间存放obj2,那么obj2和obj1就会相互独立。所以以下举例深拷贝例子。

ini 复制代码
var obj1={
   name:'我是初始值',
   age:18
};
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.name = 'meimei';

console.log(obj1);//{name:'我是初始值',age:18}
console.log(obj2);//{name:'meimei',age:18}

通过上述举例使用了深拷贝后,两个对象互不影响,深拷贝在实际开发中要经常用到所以下面总结了几种常用的深拷贝方式,并且说明了每种的缺点防止在项目中出现异常还不知道原因。

几种深拷贝方式与它们的坑

方式一: 使用JSON.stringify() 和 JSON.parse()

javascript 复制代码
let obj = {
   a:NaN,
   b: undefined,
   c:new Date(),
   d:new RegExp(/\d/),
   d:new Error(),
   e:Infinity
}
let deepObj = JSON.parse(JSON.stringify(obj))

缺陷:

(1)NaN ==> null

(2)undefined ==> 空

(3)时间戳 ==> 字符串时间

(4)错误信息 ==> 空对象

(5)Infinity ==> null

(6)无法实现对象中方法(fountion)的深拷贝

方式二: 使用拓展运算符与Object.assign()

ini 复制代码
let obj = {name:'Aos',age:25}; 

let obj2 = {...obj} 

var obj3 = Object.assign({},obj);

优点:数量较少的时候使用方便、简单,

缺点:只能拷贝外层不能拷贝内层,遇到对象或数组键比较多时,操作不方便

方式三:...解构赋值

ini 复制代码
let aa = { age: 18, name: 'aaa' } 

let bb = {...aa}; 

bb.age = 22; 

console.log(aa.age); // 18

如果只是一层数组或是对象,其元素只是简单类型的元素,那么属于深拷贝(就是一层拷贝,暂时就理解为深拷贝吧!!!!)

方式四: 递归深拷贝是完美的项目中可以自己封装使用

javascript 复制代码
function deepClone( source ) {
	if (!isObject(source)) return source; //如果不是对象的话直接返回
    if (Array.isArray(source)) {
		// 若传入的参数是数组类型, 遍历数组,递归调用
		var _arr = []
		for(let i=0; i<source.length; i++){
			_arr.push(deepClone(source[i])
		}
		return _arr
	} else{
		// 若传入的参数是对象类型,遍历对象中的key:value对,递归调用
		var _obj = {}
		for( var k in source){
			_obj[k] = deepClone(source[k])
		}
		return _obj
	}
}

function isObject(obj) {
	//注意点:null的typeof也是object
    return typeof obj === 'object' && obj !== null
}
相关推荐
程序员猫哥_2 分钟前
HTML 生成网页工具推荐:从手写代码到 AI 自动生成网页的进化路径
前端·人工智能·html
龙飞053 分钟前
Systemd -systemctl - journalctl 速查表:服务管理 + 日志排障
linux·运维·前端·chrome·systemctl·journalctl
我爱加班、、8 分钟前
Websocket能携带token过去后端吗
前端·后端·websocket
AAA阿giao8 分钟前
从零拆解一个 React + TypeScript 的 TodoList:模块化、数据流与工程实践
前端·react.js·ui·typescript·前端框架
杨超越luckly14 分钟前
HTML应用指南:利用GET请求获取中国500强企业名单,揭秘企业增长、分化与转型的新常态
前端·数据库·html·可视化·中国500强
hedley(●'◡'●)44 分钟前
基于cesium和vue的大疆司空模仿程序
前端·javascript·vue.js·python·typescript·无人机
qq5_8115175151 小时前
web城乡居民基本医疗信息管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
前端·vue.js·spring boot
百思可瑞教育1 小时前
构建自己的Vue UI组件库:从设计到发布
前端·javascript·vue.js·ui·百思可瑞教育·北京百思教育
百锦再1 小时前
Vue高阶知识:利用 defineModel 特性开发搜索组件组合
前端·vue.js·学习·flutter·typescript·前端框架
CappuccinoRose1 小时前
JavaScript 学习文档(二)
前端·javascript·学习·数据类型·运算符·箭头函数·变量声明