前言:

 本文主要阅读对象:对深浅拷贝印象模糊对初级前端,想对js深浅拷贝聊一聊的中级前端。如果是对这些有完整对认知体系和解决方法的大佬,可以选择略过。
复制代码

正文: 讨论深浅拷贝,首先要从js的基本数据类型说起: 根据 JavaScript 中的变量类型传递方式,分为值类型和引用类型, 值类型变量包括 Boolean、String、Number、Undefined、Null。
引用类型包括了 Object 类的所有, 如 Date、Array、Function 等。在参数传递方式上,值类型是按值传递,引用类型是按地址传递。

我们来看一下这两则有什么区别:

//eg1:
// 值类型
var a = 10
var b = a
b = 20
console.log(a)  // 10
console.log(b)  // 20//解析:上述代码中,a b都是值类型,两者分别修改赋值,相互之间没有任何影响。再看引用类型的例子://eg2
// 引用类型
var a = {x: 10, y: 20}
var b = a
b.x = 100
b.y = 200
console.log(a)  // {x: 100, y: 200}
console.log(b)  // {x: 100, y: 200}
复制代码

解析: 上述代码中,a b都是引用类型。在执行了b = a之后,修改b的属性值,a的也跟着变化。因为a和b都是引用类型,指向了同一个内存地址,即两者引用的是同一个值,因此b修改属性时,a的值随之改动。

**那到底什么是深浅拷贝呢?**
<br />解析:深浅拷贝是拷贝对象的`深度`来说的:
<br />当你想拷贝的对象只有一级时,就是浅拷贝。
<br />当你拷贝的对象有多级的时候,就是深拷贝。
复制代码

再回到上面的那个例子: 在例子能看出来,如果直接采用“=”赋值,这种类型,当我们改变b的值时候,a也会随之改变的,假如不允许改变a呢? 这时,深拷贝就出场了。

 function clone(val){if(!val && typeof val !== 'object'){return}const newArr = toString.call(val) === ['object Array'] ? [] : {}for (let item in val) {if(typeof val[item] ===  'object') {newArr[item] = clone(item)}else {newArr[item] = val[item]}}return newArr}//测试:var a = {x: 10, y: 20}var b = clone(a)b.x = 100b.y = 200console.log(a)  // {x: 10, y: 20}console.log(b)  //{x: 100, y: 200}复制代码

解析: 对于这个深拷贝,大家看到这里应该都可以看明白:主要思路就是浅拷贝 + 递归。
这有几个点需要注意:
1. 判断接收到的参数类型。
2. 使用toString.call()判断更加严谨。
3. 考虑对其他引用类型的数据兼容(这里并没有对每种类型的数据组做判断,引用类型包括了 Object 类的所有,如 Date、Array、Function 等。)

需要注意的是:用递归的话,会有一下几个需要特别注意的点:1. 当数据层次很深时,容易爆栈(栈溢出) 解决办法=>a. 消除尾递归b. 改用循环2. “循环引用”,会导致死循环  解决办法 =>a. 循环检测b. 暴力破解第一种:数据广度特别大,层次特别深
第二种:类似下面的这种情况var a = {}a.a = aclone(a) //死循环ES6中一行代码实现深拷贝:JSON.parse(JSON.stringify(source))
注释:JSON.stringify()其实利用了“循环检测”机制
复制代码

这里给大家推荐一篇循环解决递归的方法: 可以保持拷贝数据以后的引用关系

function cloneForce(x) {const uniqueList = []; // 用来去重let root = {};// 循环数组const loopList = [{parent: root,key: undefined,data: x,}];while(loopList.length) {// 深度优先const node = loopList.pop();const parent = node.parent;const key = node.key;const data = node.data;// 初始化赋值目标,key为undefined则拷贝到父元素,否则拷贝到子元素let res = parent;if (typeof key !== 'undefined') {res = parent[key] = {};}// 数据已经存在let uniqueData = find(uniqueList, data);if (uniqueData) {parent[key] = uniqueData.target;continue; // 中断本次循环}// 数据不存在// 保存源数据,在拷贝数据中对应的引用uniqueList.push({source: data,target: res,});for(let k in data) {if (data.hasOwnProperty(k)) {if (typeof data[k] === 'object') {// 下一次循环loopList.push({parent: res,key: k,data: data[k],});} else {res[k] = data[k];}}}}return root;
}function find(arr, item) {for(let i = 0; i < arr.length; i++) {if (arr[i].source === item) {return arr[i];}}return null;
}//eg1:
var a = {a1: b,a2: b,
}var b = {};a.a1 === a.a2 // truevar c = cloneForce(a);
c.a1 === c.a2 // true   引用保持一致//eg2:
var a = {};
a.a = a;console.log(cloneForce(a))//还可以破解循环引用
复制代码

主要思路是: 声明一个数组对象(父对象,key,value),其有值时,取其最后一个对象; 判断key有值,代表当前级下有子级,则拷贝到子元素。如果数据已经存在,则中断本次循环。数据不存在则对其拷贝。
有一点需要注意:cloneForce在对象数量很多时会出现很大的问题,如果数据量很大不适合使用cloneForce。

有兴趣的同学,可以前往 深拷贝的终极探索(90%的人都不知道),查看更多的细节。

总结:
如果觉得对你有帮助,请给作者一点小小的鼓励, 点个赞或者收藏吧。 有需要沟通的请联系我: 微信( wx9456d )邮箱( allan_liu986@163.com )

9012年,当我们讨论js深浅拷贝时我们在说些什么?相关推荐

  1. 实现JS深浅拷贝的五种方式

    一.堆栈.基本数据类型.引用数据类型 在了解深浅拷贝之前,我们需得对堆栈.基本数据类型.引用数据类型有基本的了解 基本数据类型:number.string.boolean.null.undefined ...

  2. 【学姐面试宝典】前端基础篇Ⅴ——JS深浅拷贝、箭头函数、事件监听等

    前言 博主主页

  3. JS中深浅拷贝 函数封装代码

    一.了解 基本数据类型保存在栈内存中,按值访问,引用数据类型保存在堆内存中,按址访问. 二.浅拷贝 浅拷贝只是复制了指向某个对象的指针,而不是复制对象本身,新旧对象其实是同一内存地址的数据,修改其中一 ...

  4. Python深浅拷贝!

    Python深浅拷贝! 今天博主跟大家聊一聊如何使用Python深浅拷贝!不喜勿喷,如有建议欢迎补充.讨论! 关于安装和汉化可以观看博主的这篇文章<下载安装及汉化 >以及Python系列: ...

  5. 测试开发python面试_python测试开发面试之深浅拷贝

    先来道题热热身 a = ('a', 'b','c') c = copy.copy(a) d = copy.deepcopy(a) if c == d: print("c和d的值相等" ...

  6. python测试开发面试题_python测试开发面试之深浅拷贝

    先来道题热热身 a = ('a', 'b','c') c = copy.copy(a) d = copy.deepcopy(a) if c == d: print("c和d的值相等" ...

  7. python测试开发面试之深浅拷贝【拼多多】

    先来道题热热身 a = ('a', 'b','c') c = copy.copy(a) d = copy.deepcopy(a) if c == d: print("c和d的值相等" ...

  8. JS 中对象的深浅拷贝(ES3、ES5、ES6不同方法底层实现,一文搞清楚深浅拷贝面试常问题)

    JS 中对象的深浅拷贝   拷贝我们都知道这个词的意思,我们经常做过复制.粘贴的操作,其中的复制就是拷贝,那么在拷贝的时候,如果我们复制出来的内容和原内容是完全的分开,各自不相影响,那么这就属于深拷贝 ...

  9. php深浅拷贝,js实现深浅拷贝方法

    说起深浅拷贝,我觉得需要理清楚 值类型 和 引用类型,本文主要和大家分享js实现深浅拷贝方法,希望能帮助到大家. 值类型 所谓 值类型 就是 undefined,null,number, string ...

最新文章

  1. python datetime计算时间差_用datetime计算时间差
  2. 04-图像的形状绘制
  3. 全球44家机构,55位大佬,历时两年,打造最强NLG评测基准!
  4. 2020年灵活用工行业研究报告
  5. Tachyou alluxio初识
  6. Multiple CPUs,Multiple Cores、Hyper-Threading
  7. excel粘贴为图片不完整_excel转PDF不完整?办公大神的压箱绝技来了!
  8. 计算机位数怎么看win10,怎么查看Win10是32位还是64位操作系统?
  9. Mapped Statements collection already contains value for com.bai.dao.Userdao.UserByID
  10. 什么是词频?词频的原理是什么?
  11. 2020-10-16
  12. 企业在项目中采用工时管理系统的好处
  13. 有没有游泳可以戴的耳机、防水耳机能戴着游泳
  14. DETR3D模型源码导读 MMDetection3D构建流程
  15. 带有en的单词有哪些_en押韵的词语
  16. Ingress基本故障排除方法
  17. Docker 部署 FreeIPA 服务
  18. 终于解决了hao123锁定主页的问题~
  19. 8代CPU安装Ubuntu14.04教程(解决无线无能用分辨率低问题)
  20. [词性] 十、介词 1 [ in ]

热门文章

  1. 你是... (我爱我家)
  2. 介绍一个我创业的朋友
  3. 学习分享——基于深度学习的NILM负荷分解(二)电器数据提取
  4. 抖音容易涨粉丝的视频类型
  5. 硕士毕业论文撰写记事
  6. js 解决页面切换时,定时器setInterval 会变得越来越慢
  7. excel如何做条件判断
  8. 华为笔试机考题库2023【区域发电量统计】
  9. 捡石头推荐地:玉龙雪山
  10. oracle 去空格 换行符,ORACLE:除去回车符,换行符