怎么使用javascript深度拷贝一个数组


Posted in Javascript onJune 06, 2019

有两种数组拷贝类型:浅拷贝 & 深拷贝。浅拷贝只会拷贝数组的第一层,剩下的会引用。如果你需要一个嵌套的数组的拷贝,那需要你去深度拷贝这个数组。深拷贝,选择JSON方法或者Lodsh库吧

const numbers = [1, [2], [3, [4]], 5];
// Using JavaScript
JSON.parse(JSON.stringify(numbers));
// Using Lodash
_.cloneDeep(objects);

数组是引用类型

为了搞清楚为什么有两种类型的拷贝,我们来深度了解一下基础知识然后解释什么是引用类型。
与原始类型(number、string)不同,数组是引用类型。这意味着当你把一个数组赋值给一个变量,你是将数组的内存地址而非数组本身赋给变量。

拷贝值类型

这里没什么大不了的,我们创建一个value的拷贝。当我们改变valueCopy的值,它不会影响原来的value值。同理,当我们改变原来的值它也不会影响拷贝后的值。很好?

let value = 3;
let valueCopy = value; // create copy
console.log(valueCopy); // 3
// Change valueCopy
valueCopy = 100
console.log(valueCopy); // 100
// ✅ Original NOT affected 
console.log(value); // 3

拷贝引用类型

好的,这里就会有点奇怪了!我们用同样的方法拷贝数组。

let array = [1,2,3];
let arrayCopy = array; // create copy
console.log(arrayCopy); // [1,2,3];
// Change 1st element of the array
arrayCopy[0] = '?';
console.log(arrayCopy); // [ '?', 2, 3 ]
// ❌Original got affected
console.log(array); // [ '?', 2, 3 ]

为什么原来的数组也受到了影响呢?好了,是因为:你拷贝的不是你拷贝的。说人话,意思就是你拷贝的只是指向数组内存空间的指针。引用类型不包含值,它们是指向内存中值的指针。

拷贝引用类型的方法

解决方法就是拷贝值而不是指针。

let array = [1,2,3];
let arrayCopy = [...array]; // create TRUE copy
console.log(arrayCopy); // [1,2,3];
// Change 1st element of the array
arrayCopy[0] = '?';
console.log(arrayCopy); // [ '?', 2, 3 ]
// ✅ Original NOT affected 
console.log(array); // [ 1, 2, 3 ]

浅 & 深 拷贝

当我使用展开扩展符号...来拷贝一个数组,我只是浅拷贝了一个数组。如果数组是嵌套或者多维的,这就不奏效了。

let nestedArray = [1, [2], 3];
let arrayCopy = [...nestedArray];
// Make some changes
arrayCopy[0] = '?'; // change shallow element
arrayCopy[1][0] = '?'; // change nested element
console.log(arrayCopy); // [ '?', [ '?' ], 3 ]
// ❌ Nested array got affected
console.log(nestedArray); // [ 1, [ '?' ], 3 ]

如上,浅拷贝首层数组表现良好,然而,更改了嵌套数组元素,原始数组也受到影响?。为了解决这个问题,就要用到深拷贝了。

let nestedArray = [1, [2], 3];
let arrayCopy = JSON.parse(JSON.stringify(nestedArray));
// Make some changes
arrayCopy[0] = '?'; // change shallow element
arrayCopy[1][0] = '?'; // change nested element
console.log(arrayCopy); // [ '?', [ '?' ], 3 ]
// ✅ Nested array NOT affected
console.log(nestedArray); // 1, [ 2 ], 3 ]

所以,这就完事了吗?要不要手写一个深拷贝引用类型的方法?

const deepClone = obj => {
const isObject = args => (typeof args === 'object' || typeof args === 'function') && typeof args !== null
if (!isObject) throw new Error('Not Reference Types')
let newObj = Array.isArray(obj) ? [...obj] : { ...obj }
Reflect.ownKeys(newObj).map(key => {
newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
})
return newObj
}

文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,

Javascript 相关文章推荐
数组方法解决JS字符串连接性能问题有争议
Jan 12 Javascript
jQuery动态添加及删除表单上传元素的方法(附demo源码下载)
Jan 15 Javascript
js实现滚动条滚动到某个位置便自动定位某个tr
Jan 20 Javascript
一步一步封装自己的HtmlHelper组件BootstrapHelper(二)
Sep 14 Javascript
详解Angular.js的$q.defer()服务异步处理
Nov 06 Javascript
canvas知识总结
Jan 25 Javascript
理解javascript中的Function.prototype.bind的方法
Feb 03 Javascript
JS排序之冒泡排序详解
Apr 08 Javascript
深入理解Puppeteer的入门教程和实践
Mar 05 Javascript
详释JavaScript执行环境与执行栈
Apr 02 Javascript
keep-Alive搭配vue-router实现缓存页面效果的示例代码
Jun 24 Javascript
如何在postman中添加cookie信息步骤解析
Jun 30 Javascript
微信小程序如何使用globalData的方法
Jun 06 #Javascript
详解微信小程序开发(项目从零开始)
Jun 06 #Javascript
vue如何自动化打包测试环境和正式环境的dist/test文件
Jun 06 #Javascript
jQuery+ajax实现批量删除功能完整示例
Jun 06 #jQuery
JS根据json数组多个字段排序及json数组常用操作
Jun 06 #Javascript
了解在JavaScript中将值转换为字符串的5种方法
Jun 06 #Javascript
Vue项目总结之webpack常规打包优化方案
Jun 06 #Javascript
You might like
屏蔽浏览器缓存另类方法
2006/10/09 PHP
php 日期和时间的处理-郑阿奇(续)
2011/07/04 PHP
RR vs IO BO3 第一场2.13
2021/03/10 DOTA
JavaScript Date对象使用总结
2009/05/14 Javascript
COM中获取JavaScript数组大小的代码
2009/11/22 Javascript
javascript event 事件解析
2011/01/31 Javascript
原生javascript和jquery判断浏览器版本等信息
2013/07/04 Javascript
js同比例缩放图片的小例子
2013/10/30 Javascript
js改变embed标签src值的方法
2015/04/10 Javascript
js实现iframe框架取值的方法(兼容IE,firefox,chrome等)
2015/11/26 Javascript
Bootstrap3 datetimepicker控件使用实例
2016/12/13 Javascript
关于javascript事件响应的基础语法总结(必看篇)
2016/12/26 Javascript
Angular.js中$resource高大上的数据交互详解
2017/07/30 Javascript
用jQuery将JavaScript对象转换为querystring查询字符串的方法
2018/11/12 jQuery
layer.open的自适应及居中及子页面标题的修改方法
2019/09/05 Javascript
javascript实现摄像头拍照预览
2019/09/30 Javascript
jquery添加div实现消息聊天框
2020/02/08 jQuery
html-webpack-plugin修改页面的title的方法
2020/06/18 Javascript
详谈vue中router-link和传统a链接的区别
2020/07/22 Javascript
Ant Design的可编辑Tree的实现操作
2020/10/31 Javascript
[35:55]完美世界DOTA2联赛PWL S3 Rebirth vs CPG 第一场 12.11
2020/12/13 DOTA
python处理cookie详解
2014/02/07 Python
Python脚本在Appium库上对移动应用实现自动化测试
2015/04/17 Python
Python干货:分享Python绘制六种可视化图表
2018/08/27 Python
Python学习笔记之Zip和Enumerate用法实例分析
2019/08/14 Python
解决Django删除migrations文件夹中的文件后出现的异常问题
2019/08/31 Python
HTML5的结构和语义(1):前言
2008/10/17 HTML / CSS
Silk’n激光脱毛器官网:silkn.com
2016/10/06 全球购物
个性车贴标语
2014/06/24 职场文书
计划生育证明格式范本
2014/09/12 职场文书
老人节标语大全
2014/10/08 职场文书
2014年幼儿园安全工作总结
2014/11/10 职场文书
个人年终总结范文
2015/03/09 职场文书
会议主持词结束语
2015/07/03 职场文书
JavaScript使用canvas绘制坐标和线
2021/04/28 Javascript
win11高清晰音频管理器在哪里?win11找不到高清晰音频管理器解决办法
2022/04/08 数码科技