怎么使用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 DOM模型操作
Dec 28 Javascript
json2.js的初步学习与了解
Oct 06 Javascript
javascript的字符串按引用复制和传递,按值来比较介绍与应用
Dec 28 Javascript
原生js事件的添加和删除的封装
Jul 01 Javascript
Jquery实现鼠标移动放大图片功能实例
Mar 25 Javascript
JavaScript鼠标特效大全
Sep 13 Javascript
AngularJS入门教程之数据绑定原理详解
Nov 02 Javascript
关于vuex的学习实践笔记
Apr 05 Javascript
基于vue2.0实现的级联选择器
Jun 09 Javascript
jQuery Validate插件ajax方式验证输入值的实例
Dec 21 jQuery
微信实现自动跳转到用其他浏览器打开指定APP下载
Feb 15 Javascript
了解javascript中变量及函数的提升
May 27 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
Linux下CoreSeek及PHP扩展模块的安装
2012/09/23 PHP
PHP查询快递信息的方法
2015/03/07 PHP
PHP7新增运算符用法实例分析
2016/09/26 PHP
mysql输出数据赋给js变量报unterminated string literal错误原因
2010/05/22 Javascript
一次失败的jQuery优化尝试小结
2011/02/06 Javascript
基于javascript实现泡泡大冒险网页版小游戏
2016/03/23 Javascript
jQuery EasyUI封装简化操作
2016/09/18 Javascript
easyui datagrid 大数据加载效率慢,优化解决方法(推荐)
2016/11/09 Javascript
微信小程序之小豆瓣图书实例
2016/11/30 Javascript
bootstrap multiselect 多选功能实现方法
2017/06/05 Javascript
JS利用正则表达式实现简单的密码强弱判断实例
2017/06/16 Javascript
JavaScript学习总结(一) ECMAScript、BOM、DOM(核心、浏览器对象模型与文档对象模型)
2018/01/07 Javascript
浅谈AngularJS中$http服务的简单用法
2018/05/15 Javascript
vue.js 添加 fastclick的支持方法
2018/08/28 Javascript
微信小程序利用button控制条件标签的变量问题
2020/03/15 Javascript
解决React在安装antd之后出现的Can't resolve './locale'问题(推荐)
2020/05/03 Javascript
JS出现404错误原理及解决方案
2020/07/01 Javascript
python使用pil生成图片验证码的方法
2015/05/08 Python
Python中list初始化方法示例
2016/09/18 Python
浅谈Python实现2种文件复制的方法
2018/01/19 Python
Python实现线程状态监测简单示例
2018/03/28 Python
卸载tensorflow-cpu重装tensorflow-gpu操作
2020/06/23 Python
基于css3的属性transition制作菜单导航效果
2015/09/01 HTML / CSS
详解使用HTML5的classList属性操作CSS类
2017/10/13 HTML / CSS
Otticanet英国:最顶尖的世界名牌眼镜, 能得到打折季的价格
2019/02/10 全球购物
Ibood荷兰:互联网每日最佳在线优惠
2019/02/28 全球购物
请用Java实现列出某个目录下的所有文件
2013/09/23 面试题
学生实习自我鉴定
2013/10/11 职场文书
历史专业个人求职信范文
2013/12/07 职场文书
房地产财务部员工岗位职责
2014/03/12 职场文书
政治表现评语
2014/05/04 职场文书
思想作风纪律整顿心得体会
2014/09/04 职场文书
世界遗产的导游词
2015/02/13 职场文书
撤诉状格式范本
2015/05/19 职场文书
创业计划书之零食店(进口)
2019/09/24 职场文书
Win10 和 Win11可以共存吗? win10/11产品生命周期/服务更新介绍
2021/11/21 数码科技