怎么使用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 相关文章推荐
javascript 写类方式之八
Jul 05 Javascript
javascript 程序库的比较(一)之DOM功能
Apr 07 Javascript
jquery js 获取时间差、时间格式具体代码
Jun 05 Javascript
js保留小数点后几位的写法
Jan 03 Javascript
小结Node.js中非阻塞IO和事件循环
Sep 18 Javascript
最全的JavaScript开发工具列表 总有一款适合你
Jun 29 Javascript
vue2.0 keep-alive最佳实践
Jul 06 Javascript
jQuery实现的简单拖拽功能示例【测试可用】
Aug 14 jQuery
redux.js详解及基本使用
May 24 Javascript
JS模拟浏览器实现全局搜索功能
Sep 11 Javascript
通过js实现压缩图片上传功能
Feb 25 Javascript
JavaScript进阶(一)变量声明提升实例分析
May 09 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
php 时间计算问题小结
2009/01/04 PHP
php HandlerSocket的使用
2011/05/02 PHP
Zend Framework教程之Application用法实例详解
2016/03/14 PHP
php中实现进程锁与多进程的方法
2016/09/18 PHP
php实现简单的权限管理的示例代码
2017/08/25 PHP
jQuery Validation插件remote验证方式的Bug解决
2010/07/01 Javascript
JQuery页面地址处理插件jqURL详解
2015/05/03 Javascript
AngularJS初始化静态模板详解
2016/01/14 Javascript
Bootstrap modal使用及点击外部不消失的解决方法
2016/12/13 Javascript
Bootstrap模态框(Modal)实现过渡效果
2017/03/17 Javascript
ES6新特性二:Iterator(遍历器)和for-of循环详解
2017/04/20 Javascript
jquery实现限制textarea输入字数的方法
2017/09/06 jQuery
详解Vue路由History mode模式中页面无法渲染的原因及解决
2017/09/28 Javascript
深入理解Angular4订阅(Subscribe)与取消
2017/11/22 Javascript
使用puppeteer破解极验的滑动验证码
2018/02/24 Javascript
微信小程序中使用ECharts 异步加载数据实现图表功能
2018/07/13 Javascript
Angular2实现的秒表及改良版示例
2019/05/10 Javascript
JS数组扁平化(flat)方法总结详解
2019/06/24 Javascript
vue 检测用户上传图片宽高的方法
2020/02/06 Javascript
Python中集合类型(set)学习小结
2015/01/28 Python
Python实现的数据结构与算法之队列详解
2015/04/22 Python
给Python中的MySQLdb模块添加超时功能的教程
2015/05/05 Python
linux平台使用Python制作BT种子并获取BT种子信息的方法
2017/01/20 Python
使用python 3实现发送邮件功能
2018/06/15 Python
pygame游戏之旅 游戏中添加显示文字
2018/11/20 Python
选择python进行数据分析的理由和优势
2019/06/25 Python
python批量修改图片尺寸,并保存指定路径的实现方法
2019/07/04 Python
python爬虫要用到的库总结
2020/07/28 Python
Dillard’s百货官网:Dillards.com
2018/05/26 全球购物
意大利单身交友网站:Meetic
2020/07/12 全球购物
外贸销售员求职的自我评价
2013/11/23 职场文书
计划生育证明格式及范本
2014/10/09 职场文书
2014年司机工作总结
2014/11/21 职场文书
幼儿学前班评语
2014/12/29 职场文书
2016年国培研修日志
2015/11/13 职场文书
教你怎么用Python处理excel实现自动化办公
2021/04/30 Python