怎么使用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学习笔记6 prototype的提出
Jan 11 Javascript
Json对象与Json字符串互转(4种转换方式)
Mar 27 Javascript
js播放wav文件(源码)
Apr 22 Javascript
jQuery表单验证简单示例
Oct 17 Javascript
微信小程序中多个页面传参通信的学习与实践
May 05 Javascript
关于页面刷新vuex数据消失问题解决方案
Jul 03 Javascript
Bootstrap3.3.7导航栏下拉菜单鼠标滑过展开效果
Oct 31 Javascript
Vue实现动态创建和删除数据的方法
Mar 17 Javascript
详解Vue的钩子函数(路由导航守卫、keep-alive、生命周期钩子)
Jul 24 Javascript
在小程序/mpvue中使用flyio发起网络请求的方法
Sep 13 Javascript
Vue指令指令大全
Feb 09 Javascript
JS倒计时两种实现方式代码实例
Jul 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
图象函数中的中文显示
2006/10/09 PHP
推荐Discuz!5的PHP代码高亮显示与实现可运行代码
2007/03/15 PHP
PHP生成随机用户名和密码的实现代码
2013/02/27 PHP
取得单条网站评论以数组形式进行输出
2014/07/28 PHP
详解php比较操作符的安全问题
2015/12/03 PHP
php中的异常和错误浅析
2017/05/03 PHP
PHP实现的获取文件mimes类型工具类示例
2018/04/08 PHP
php过滤htmlspecialchars() 函数实现把预定义的字符转换为 HTML 实体用法分析
2019/06/25 PHP
jquery attr 设定src中含有&(宏)符号问题的解决方法
2011/07/26 Javascript
jquery不会自动回收xmlHttpRequest对象 导致了内存溢出
2012/06/18 Javascript
Js中setTimeout()和setInterval() 何时被调用执行的用法
2013/04/12 Javascript
jQuery解析XML文件同时动态增加js文件的方法
2015/06/01 Javascript
Bootstrap树形控件使用方法详解
2016/01/27 Javascript
jQuery Select下拉框操作小结(推荐)
2016/07/22 Javascript
COM组件中调用JavaScript函数详解及实例
2017/02/23 Javascript
JavaScript和jQuery制作光棒效果
2017/02/24 Javascript
Bootstrap常用组件学习(整理)
2017/03/24 Javascript
Nodejs读取文件时相对路径的正确写法(使用fs模块)
2017/04/27 NodeJs
js 概率计算(简单版)
2017/09/12 Javascript
vue.js 实现点击展开收起动画效果
2018/07/07 Javascript
JS使用JSON.parse(),JSON.stringify()实现对对象的深拷贝功能分析
2019/03/06 Javascript
JavaScript惰性载入函数实例分析
2019/03/27 Javascript
vue项目中mock.js的使用及基本用法
2019/05/22 Javascript
python改变日志(logging)存放位置的示例
2014/03/27 Python
Python使用Beautiful Soup包编写爬虫时的一些关键点
2016/01/20 Python
Python遍历文件夹和读写文件的实现代码
2016/08/28 Python
Python实现FTP上传文件或文件夹实例(递归)
2017/01/16 Python
Python 爬虫图片简单实现
2017/06/01 Python
用Python制作mini翻译器的实现示例
2020/08/17 Python
详解python对象之间的交互
2020/09/29 Python
使用CSS3创建动态菜单效果
2015/07/10 HTML / CSS
英国最大的在线床超市:Bed Star
2019/01/24 全球购物
工程班组长岗位职责
2013/12/30 职场文书
活动总结书怎么写
2015/05/11 职场文书
发票退票证明
2015/06/24 职场文书
基督教追悼会答谢词
2015/09/29 职场文书