JavaScript中十种一步拷贝数组的方法实例详解
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(浅拷贝)
上面的for和while都是很“古老”的方式,让我们继续回到当前,我们会发现map方法。map源于数学,是将一个集合转换成另一种集合,保留结构的概念。
在英语中,它意味着Array.map 每次返回相同长度的数组。
numbers = [1, 2, 3]; double = (x) => x 2; numbers.map(double);
当我们使用map方法时,需要给出一个callback函数用于处理当前的数组,并返回一个新的数组元素。
和拷贝数组有什么关系呢?
当我们想要复制一个数组的时候,只需要在map的callback函数中直接返回原数组的元素即可。
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, ss 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 pletely 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)
9、Array.cancat(浅拷贝)
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]同样的,处理对象和数组的时候是引用而不是值复制。
小结
上面这些方法都是在使用一个步骤来进行拷贝。如果我们结合一些其他的方法或技术能够发现还有很多的方式来实现数组的拷贝,比如一系列的拷贝工具函数等。
以上所述是长沙网络推广给大家介绍的JavaScript中十种一步拷贝数组的方法实例详解,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,长沙网络推广会及时回复大家的!
编程语言
- 如何快速学会编程 如何快速学会ug编程
- 免费学编程的app 推荐12个免费学编程的好网站
- 电脑怎么编程:电脑怎么编程网咯游戏菜单图标
- 如何写代码新手教学 如何写代码新手教学手机
- 基础编程入门教程视频 基础编程入门教程视频华
- 编程演示:编程演示浦丰投针过程
- 乐高编程加盟 乐高积木编程加盟
- 跟我学plc编程 plc编程自学入门视频教程
- ug编程成航林总 ug编程实战视频
- 孩子学编程的好处和坏处
- 初学者学编程该从哪里开始 新手学编程从哪里入
- 慢走丝编程 慢走丝编程难学吗
- 国内十强少儿编程机构 中国少儿编程机构十强有
- 成人计算机速成培训班 成人计算机速成培训班办
- 孩子学编程网上课程哪家好 儿童学编程比较好的
- 代码编程教学入门软件 代码编程教程