JavaScript中我们经常会遇到拷贝数组的场景,但是都有哪些方式能够来实现呢,我们不妨来梳理一下。

1、扩展运算符(浅拷贝)

自从ES6出现以来,这已经成为最流行的方法。它是一个很简单的语法,但是当你在使用类似于React和Redux这类库时,你会发现它是非常非常有用的。

numbers = [1, 2, 3];
numbersCopy = [...numbers];
复制代码

这个方法不能有效的拷贝多维数组。数组/对象值的拷贝是通过引用而不是值复制。

// ?
numbersCopy.push(4);
console.log(numbers, numbersCopy);
// [1, 2, 3] and [1, 2, 3, 4]
// 只修改了我们希望修改的,原数组不受影响// ?
nestedNumbers = [[1], [2]];
numbersCopy = [...nestedNumbers];
numbersCopy[0].push(300);
console.log(nestedNumbers, numbersCopy);
// [[1, 300], [2]]
// [[1, 300], [2]]
// 由于公用引用,所以两个数组都被修改了,这是我们不希望的
复制代码

2、for()循环(浅拷贝)

考虑到函数式编程变得越来越流行,我认为这种方法可能是最不受欢迎的。


numbers = [1, 2, 3];
numbersCopy = [];
for (i = 0; i < numbers.length; i++) {numbersCopy[i] = numbers[i];
}复制代码

这个方法不能有效的拷贝多维数组。因为我们使用的是=运算符,它在处理数组/对象值的拷贝时通过引用而不是值复制。

// ?
numbersCopy.push(4);
console.log(numbers, numbersCopy);
// [1, 2, 3] and [1, 2, 3, 4]// ?
nestedNumbers = [[1], [2]];
numbersCopy = [];
for (i = 0; i < nestedNumbers.length; i++) {numbersCopy[i] = nestedNumbers[i];
}
numbersCopy[0].push(300);
console.log(nestedNumbers, numbersCopy);
// [[1, 300], [2]]
// [[1, 300], [2]]
// 由于公用引用,所以两个数组都被修改了,这是我们不希望的复制代码

3、while()循环(浅拷贝)

for() 类似。

numbers = [1, 2, 3];
numbersCopy = [];
i = -1;
while (++i < numbers.length) {numbersCopy[i] = numbers[i];
}
复制代码

4、Array.map(浅拷贝)

上面的forwhile都是很“古老”的方式,让我们继续回到当前,我们会发现map方法。map源于数学,是将一个集合转换成另一种集合,同时保留结构的概念。

在英语中,它意味着Array.map 每次返回相同长度的数组。

numbers = [1, 2, 3];
double = (x) => x * 2;numbers.map(double);
复制代码

当我们使用map方法时,需要给出一个callback函数用于处理当前的数组,并返回一个新的数组元素。

和拷贝数组有什么关系呢?

当我们想要复制一个数组的时候,只需要在mapcallback函数中直接返回原数组的元素即可。

numbers = [1, 2, 3];
numbersCopy = numbers.map((x) => x);
复制代码

如果你想更数学化一点,(x) => x叫做恒等式。它返回给定的任何参数。

identity = (x) => x;
numbers.map(identity);
// [1, 2, 3]
复制代码

同样的,处理对象和数组的时候是引用而不是值复制。

5、Array.filter(浅拷贝)

Array.filter方法同样会返回一个新数组,但是并不一定是返回同样长度的,这和我们的过滤条件有关。

[1, 2, 3].filter((x) => x % 2 === 0)
// [2]
复制代码

当我们的过滤条件总是true时,就可以用来实现拷贝。

numbers = [1, 2, 3];
numbersCopy = numbers.filter(() => true);
// [1, 2, 3]
复制代码

同样的,处理对象和数组的时候是引用而不是值复制。

6、Array.reduce(浅拷贝)

其实用reduce来拷贝数组并没有展示出它的实际功能,但是我们还是要将其能够拷贝数组的能力说一下的

numbers = [1, 2, 3];
numbersCopy = numbers.reduce((newArray, element) => {newArray.push(element);return newArray;
}, []);
复制代码

reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数,将其结果汇总为单个返回值。

上面我们的例子中初始值是一个空数组,我们在遍历原数组的时候来填充这个空数组。该数组必须要从下一个迭代函数的执行后被返回出来。

同样的,处理对象和数组的时候是引用而不是值复制。

7、Array.slice(浅拷贝)

slice 方法根据我们指定的start、end的index从原数组中返回一个浅拷贝的数组。

[1, 2, 3, 4, 5].slice(0, 3);
// [1, 2, 3]
// Starts at index 0, stops at index 3// 当不给定参数时,就返回了原数组的拷贝
numbers = [1, 2, 3, 4, 5];
numbersCopy = numbers.slice();
// [1, 2, 3, 4, 5]
复制代码

同样的,处理对象和数组的时候是引用而不是值复制。

8、JSON.parse & JSON.stringify(深拷贝)

JSON.stringify将一个对象转成字符串; JSON.parse将转成的字符串转回对象。

将它们组合起来可以将对象转换成字符串,然后反转这个过程来创建一个全新的数据结构。

nestedNumbers = [[1], [2]];
numbersCopy = JSON.parse(JSON.stringify(nestedNumbers)
);
numbersCopy[0].push(300);
console.log(nestedNumbers, numbersCopy);
// [[1], [2]]
// [[1, 300], [2]]
// These two arrays are completely separate!
复制代码

这个可以安全地拷贝深度嵌套的对象/数组

几种特殊情况

1、如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式。而不是时间对象;

var test = {name: 'a',date: [new Date(1536627600000), new Date(1540047600000)],
};let b;
b = JSON.parse(JSON.stringify(test))
console.log(b)
复制代码

2、如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象;

const test = {name: 'a',date: new RegExp('\\w+'),
};
// debugger
const copyed = JSON.parse(JSON.stringify(test));
test.name = 'test'
console.log('ddd', test, copyed)
复制代码

3、如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失;

const test = {name: 'a',date: function hehe() {console.log('fff')},
};
// debugger
const copyed = JSON.parse(JSON.stringify(test));
test.name = 'test'
console.error('ddd', test, copyed)
复制代码

4、如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null

5、JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor;

function Person(name) {this.name = name;console.log(name)
}const liai = new Person('liai');const test = {name: 'a',date: liai,
};
// debugger
const copyed = JSON.parse(JSON.stringify(test));
test.name = 'test'
console.error('ddd', test, copyed)
复制代码

参考文章:关于JSON.parse(JSON.stringify(obj))实现深拷贝应该注意的坑

9、Array.concat(浅拷贝)

concat将数组与值或其他数组进行组合。

[1, 2, 3].concat(4); // [1, 2, 3, 4]
[1, 2, 3].concat([4, 5]); // [1, 2, 3, 4, 5]
复制代码

如果我们不指定参数或者提供一个空数组作为参数,就可以进行浅拷贝。

[1, 2, 3].concat(); // [1, 2, 3]
[1, 2, 3].concat([]); // [1, 2, 3]
复制代码

同样的,处理对象和数组的时候是引用而不是值复制。

10、Array.from(浅拷贝)

可以将任何可迭代对象转换为数组。给一个数组返回一个浅拷贝。

console.log(Array.from('foo'))
// ['f', 'o', 'o']numbers = [1, 2, 3];
numbersCopy = Array.from(numbers)
// [1, 2, 3]
复制代码

同样的,处理对象和数组的时候是引用而不是值复制。


小结

上面这些方法都是在使用一个步骤来进行拷贝。如果我们结合一些其他的方法或技术能够发现还有很多的方式来实现数组的拷贝,比如一系列的拷贝工具函数等。


原文地址: How to clone an array in JavaScript


关注微信公众号同步推送更新

或者可以去Github上面给个Star

转载于:https://juejin.im/post/5cbd6052e51d456e845b421a

JavaScript中十个一步拷贝数组的方法相关推荐

  1. JavaScript中十种一步拷贝数组的方法

    JavaScript中我们经常会遇到拷贝数组的场景,但是都有哪些方式能够来实现呢,我们不妨来梳理一下. 1.扩展运算符(浅拷贝) 自从ES6出现以来,这已经成为最流行的方法.它是一个很简单的语法,但是 ...

  2. JavaScript 中 15 种常见的数组操作

    本文 GitHub https://github.com/qq44924588... 上已经收录,更多往期高赞文章的分类,也整理了很多我的文档,和教程资料.欢迎Star和完善,大家面试可以参照考点复习 ...

  3. JavaScript中利用for循环遍历数组

    这篇文章主要为大家详细介绍了JavaScript中利用for循环遍历数组,最好不要使用for in遍历,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 先看一段代码 1 2 3 4 5 6 7 8 ...

  4. Javascript中关于监听DOM元素状态的方法使用

    Javascript中关于监听DOM元素状态的方法使用 MutationObserver MutationObserver是针对DOM元素的观察器,观察它体内增加/减少子(爷孙)节点,或者子节点的属性 ...

  5. Web前端技术分享:Javascript中的内置对象数组讲解

    有关js中的数组,很多小伙伴可能都会有疑问,尤其是面试的过程中有大量有关于原生数组的题,以及数组中的方法,及方法的返回值.是否会修改原数组等等.想要彻底解决这些问题,就要系统的解析数组的方法,那么今天 ...

  6. JavaScript中Array 对象相关的几个方法

    好记性不如烂笔头 push 方法 将新元素添加到一个数组中,并返回数组的新长度值. arrayObj.push([item1 [item2 [. . . [itemN ]]]]) 参数 arrayOb ...

  7. javascript中处理时间戳为日期格式的方法

    本文为大家介绍下javascript中如何将时间戳处理为日期格式,下面有个不错的示例,感兴趣的朋友可以参考下 公共处理时间戳函数 代码如下: /** * 处理时间戳转换成日期格式 * @param { ...

  8. javascript 中的深复制 和 其实现方法

    首先,我们需要明白什么是深复制(侧重指对象方面)? 在javascript中,复制分为浅复制和深复制,个人理解,浅复制就是直接将引用复制,复制前后的两个对象指向同一个内存地址,对其中一个进行操作,另外 ...

  9. 在 JavaScript 中访问对象属性的 3 种方法

    您可以通过 3 种方式访问 JavaScript 中对象的属性: 点属性访问器:object.property 方括号属性访问:object['property'] 对象解构:const { prop ...

最新文章

  1. poj2240(Bellman-ford)
  2. php把中文写入mysql_PHP向mysql插入中文乱码问题,php文件内容写入数据库!
  3. 19 python正则表达式及相关函数
  4. 创智播客微服务_【传智播客】JavaEE在职加薪课
  5. 转:Delphi 函数大全
  6. 【Flink】flink-connector-elasticsearch5与flink-connector-elasticsearch6 有什么区别
  7. 成为iPhone游戏开发者的十大秘技
  8. 程序员面试金典——9.4集合的子集
  9. 软工导论 12-13-2 实验任务一
  10. 8000401a 因为配置标志不正确 错误及解决办法
  11. 织梦php 文章采集规则,织梦输入网址采集单个网页功能发布 不需要写采集规则一键采集...
  12. Excel常用功能(持续更新)
  13. 贴片发光二极管/LED灯正负极判断
  14. (七)HyperledgerFarbic1.4- Fabric的SDK使用
  15. 飞秋怎么搜索指定ip好友_飞秋怎么加好友
  16. 苹果手机还原后无法激活
  17. java实现超时任务
  18. 如何为物联网解决方案选择合适的物联网模块
  19. 关于终止多个for select循环嵌套的问题
  20. 【Sass/SCSS】我花4小时整理了的Sass的函数

热门文章

  1. 03_运算符、键盘录入、流程控制
  2. C#: switch语句的重构
  3. FCKeditor的开发精简
  4. Android中的Broadcast Action大全
  5. Vue 新手学习笔记:vue-element-admin 之安装,配置及入门开发
  6. 2018.11.01 NOIP训练 cost数(搜索+容斥原理)
  7. 第二节 -- python的基础语法
  8. Destroying the bus stations
  9. CSDN总结的面试中的十大可视化工具
  10. C# 的 Console类