怎么使用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学习笔记(一) 在html中使用javascript
Jun 18 Javascript
JavaScript学习笔记之JS事件对象
Jan 22 Javascript
JS+CSS实现大气的黑色首页导航菜单效果代码
Sep 10 Javascript
jQuery中inArray方法注意事项分析
Jan 25 Javascript
jQuery tagsinput在h5邮件客户端中应用详解
Sep 26 Javascript
AngularJS入门教程之路由机制ngRoute实例分析
Dec 13 Javascript
node.js入门学习之url模块
Feb 25 Javascript
react-router4 嵌套路由的使用方法
Jul 24 Javascript
vue双花括号的使用方法 附练习题
Nov 07 Javascript
讲解vue-router之什么是动态路由
May 28 Javascript
jQuery实现表单动态添加数据并提交的方法
Jul 19 jQuery
VUE动态生成word的实现
Jul 26 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
关于URL最大长度限制的相关资料查证
2014/12/23 PHP
golang、python、php、c++、c、java、Nodejs性能对比
2017/03/12 NodeJs
PHP文字转图片功能原理与实现方法分析
2017/08/31 PHP
Laravel多用户认证系统示例详解
2018/03/13 PHP
jquery ajax 同步异步的执行 return值不能取得的解决方案
2012/01/08 Javascript
js弹出的对话窗口永远保持居中显示
2012/12/15 Javascript
javascript将数组插入到另一个数组中的代码
2013/01/10 Javascript
javascript数组遍历for与for in区别详解
2014/12/04 Javascript
JavaScript获取伪元素(Pseudo-Element)属性的方法技巧
2015/03/13 Javascript
javascript中SetInterval与setTimeout的定时器用法
2015/08/24 Javascript
JS+CSS实现简易实用的滑动门菜单效果
2015/09/18 Javascript
javascript实现抽奖程序的简单实例
2016/06/07 Javascript
基于JavaScript实现轮播图原理及示例
2020/04/10 Javascript
使用vuex解决刷新页面state数据消失的问题记录
2019/05/08 Javascript
利用Vue的v-for和v-bind实现列表颜色切换
2020/07/17 Javascript
在vue项目中引用Antv G2,以饼图为例讲解
2020/10/28 Javascript
vue祖孙组件之间的数据传递案例
2020/12/07 Vue.js
[01:45]绝对公平!DOTA2队长征召模式详解
2014/04/25 DOTA
Python简单实现查找一个字符串中最长不重复子串的方法
2018/03/26 Python
python如何创建TCP服务端和客户端
2018/08/26 Python
python常用函数与用法示例
2019/07/02 Python
Python 迭代,for...in遍历,迭代原理与应用示例
2019/10/12 Python
Python PyQt5运行程序把输出信息展示到GUI图形界面上
2020/04/27 Python
python多进程下的生产者和消费者模型
2020/05/07 Python
python3定位并识别图片验证码实现自动登录功能
2021/01/29 Python
css3动画效果小结(推荐)
2016/07/25 HTML / CSS
Vans(范斯)德国官网:美国南加州的原创极限运动潮牌
2017/05/02 全球购物
大学团日活动新闻稿
2014/09/10 职场文书
大专毕业生自我鉴定范文(2篇)
2014/09/27 职场文书
党的群众路线批评与自我批评范文
2014/10/16 职场文书
实习单位指导教师评语
2014/12/30 职场文书
八月一日观后感
2015/06/10 职场文书
2016年9月份红领巾广播稿
2015/12/21 职场文书
Redis调用Lua脚本及使用场景快速掌握
2022/03/16 Redis
Python中itertools库的四个函数介绍
2022/04/06 Python