怎么使用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 相关文章推荐
JQUERY复选框CHECKBOX全选,取消全选
Aug 30 Javascript
JS弹出层的显示与隐藏示例代码
Dec 27 Javascript
JS获取当前使用的浏览器名字以及版本号实现方法
Aug 19 Javascript
浅谈JavaScript的闭包函数
Dec 08 Javascript
bootstrap配合Masonry插件实现瀑布式布局
Jan 18 Javascript
微信JS SDK接入的几点注意事项(必看篇)
Jun 23 Javascript
浅谈express 中间件机制及实现原理
Aug 31 Javascript
Vue.js用法详解
Nov 13 Javascript
vue数据传递--我有特殊的实现技巧
Mar 20 Javascript
微信小程序实现默认第一个选中变色效果
Jul 17 Javascript
微信小程序之左右布局的实现代码
Dec 13 Javascript
原生Javascript+HTML5一步步实现拖拽排序
Jun 12 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
西德产收音机
2021/03/01 无线电
PHP与SQL注入攻击[三]
2007/04/17 PHP
PHP print类函数使用总结
2010/06/25 PHP
简单的php写入数据库类代码分享
2011/07/26 PHP
微信支付的开发流程详解
2016/09/13 PHP
php中通过eval实现字符串格式的计算公式
2017/03/18 PHP
PHP获取本周所有日期或者最近七天所有日期的方法
2018/06/20 PHP
PHP sdk实现在线打包代码示例
2020/12/09 PHP
封装的原生javascript弹出层代码
2010/09/24 Javascript
基于JQuery的日期联动实现代码
2011/02/24 Javascript
详谈 Jquery Ajax异步处理Json数据.
2011/09/09 Javascript
在Iframe中获取父窗口中表单的值(示例代码)
2013/11/22 Javascript
jquery分页插件jpaginate在IE中不兼容问题
2014/04/22 Javascript
详解JavaScript的闭包、IIFE、apply、函数与对象
2016/12/21 Javascript
微信小程序 自己制作小组件实例详解
2016/12/22 Javascript
有关JS中的0,null,undefined,[],{},'''''''',false之间的关系
2017/02/14 Javascript
React Native中TabBarIOS的简单使用方法示例
2017/10/13 Javascript
jquery ztree实现右键收藏功能
2017/11/20 jQuery
使用 Node.js 开发资讯爬虫流程
2018/01/07 Javascript
JS使用栈判断给定字符串是否是回文算法示例
2019/03/04 Javascript
layer扩展打开/关闭动画的方法
2019/09/23 Javascript
关于JSON解析的实现过程解析
2019/10/08 Javascript
[01:48]DOTA2 2015国际邀请赛中国区预选赛第二日战报
2015/05/27 DOTA
[00:12]2018DOTA2亚洲邀请赛 sylar表现SOLO技艺
2018/04/06 DOTA
python3模拟百度登录并实现百度贴吧签到示例分享(百度贴吧自动签到)
2014/02/24 Python
Python如何判断数独是否合法
2016/09/08 Python
python中defaultdict的用法详解
2017/06/07 Python
Python中如何优雅的合并两个字典(dict)方法示例
2017/08/09 Python
浅谈配置OpenCV3 + Python3的简易方法(macOS)
2018/04/02 Python
将string类型的数据类型转换为spark rdd时报错的解决方法
2019/02/18 Python
python实现密码验证合格程序的思路详解
2020/06/01 Python
Python3爬虫ChromeDriver的安装实例
2021/02/06 Python
使用HTML5做的导航条详细步骤
2020/10/19 HTML / CSS
Johnson Fitness澳大利亚:高级健身器材
2021/03/16 全球购物
商场圣诞节活动总结
2015/05/06 职场文书
Echarts如何重新渲染实例详解
2022/05/30 Javascript