怎么使用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 相关文章推荐
c#和Javascript操作同一json对象的实现代码
Jan 17 Javascript
node.js读取文件到字符串的方法
Jun 29 Javascript
JavaScript实现给按钮加上双重动作的方法
Aug 14 Javascript
jQuery实现滚动鼠标放大缩小图片的方法(附demo源码下载)
Mar 05 Javascript
JS函数arguments数组获得实际传参数个数的实现方法
May 28 Javascript
AngularJS基础 ng-mouseenter 指令示例代码
Aug 02 Javascript
Input文本框随着输入内容多少自动延伸的实现
Feb 15 Javascript
详解vue-cli 接口代理配置
Dec 13 Javascript
jquery+ajaxform+springboot控件实现数据更新功能
Jan 22 jQuery
JS字符串常用操作方法实例小结
Jun 24 Javascript
vue 取出v-for循环中的index值实例
Nov 09 Javascript
JS+HTML实现自定义上传图片按钮并显示图片功能的方法分析
Feb 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
供参考的 php 学习提高路线分享
2011/10/23 PHP
ThinkPHP的cookie和session冲突造成Cookie不能使用的解决方法
2014/07/01 PHP
php 伪造ip以及url来路信息方法汇总
2014/11/25 PHP
PHP实现格式化文件数据大小显示的方法
2015/01/03 PHP
PHP实现关键字搜索后描红功能示例
2019/07/03 PHP
JavaScript高级程序设计 阅读笔记(二十) js错误处理
2012/08/14 Javascript
Jquery写一个鼠标拖动效果实现原理与代码
2012/12/24 Javascript
如何将一个String和多个String值进行比较思路分析
2013/04/22 Javascript
JS 获取鼠标左右键的键值方法
2014/10/11 Javascript
jQuery中append()方法用法实例
2014/12/25 Javascript
Jquery zTree 树控件异步加载操作
2016/02/25 Javascript
让html元素随浏览器的大小自适应垂直居中的实现方法
2016/10/12 Javascript
js移动焦点到最后位置的简单方法
2016/11/25 Javascript
vue.js实现表格合并示例代码
2016/11/30 Javascript
javascript 面向对象function详解及实例代码
2017/02/28 Javascript
详解nodeJS之路径PATH模块
2017/05/31 NodeJs
在Vue中获取组件声明时的name属性方法
2018/09/12 Javascript
VUE v-for循环中每个item节点动态绑定不同函数的实例
2018/09/26 Javascript
JavaScript生成随机验证码代码实例
2019/09/28 Javascript
JS前端模块化原理与实现方法详解
2020/03/17 Javascript
vue中用 async/await 来处理异步操作
2020/07/18 Javascript
toString.call()通用的判断数据类型方法示例
2020/08/28 Javascript
javascript自定义加载loading效果
2020/09/15 Javascript
[01:28:24]NAVI vs VG Supermajor 败者组 BO3 第三场 6.5
2018/06/06 DOTA
[01:45]典藏宝瓶2+祈求者身心——这就是DOTA2TI9总奖金突破3000万美元的秘密
2019/07/21 DOTA
Python 26进制计算实现方法
2015/05/28 Python
WINDOWS 同时安装 python2 python3 后 pip 错误的解决方法
2017/03/16 Python
python的turtle库使用详解
2019/05/10 Python
Python 实现一行输入多个数字(用空格隔开)
2020/04/29 Python
全球摩托车装备领导者:RevZilla
2017/09/04 全球购物
优秀党员主要事迹
2014/01/19 职场文书
大班开学家长寄语
2014/04/04 职场文书
微笑服务演讲稿
2014/05/13 职场文书
拒绝黄毒毒宣传标语
2014/06/26 职场文书
社区清明节活动总结
2014/07/04 职场文书
SpringBoot2零基础到精通之异常处理与web原生组件注入
2022/03/22 Java/Android