用 JavaScript 处理很多事情,都有很多不同的方法。 我写过这篇《用 JavaScript 编写 pipe/compose 的 10 种方法》,现在我们看看数组的实现。

1、JavaScript 展开操作符(浅拷贝)

自从 ES6 发布以来,这一直是最受欢迎的方法。这是一个简短的语法,在使用 React 和 Redux 之类的库时,你会发现它非常有用。

numbers = [1, 2, 3];
numbersCopy = [...numbers];

注意:这不能安全地复制多维数组。数组/对象值是按 引用 而不是按 复制的。

这个写法很好:

numbersCopy.push(4);
console.log(numbers, numbersCopy);
// [1, 2, 3] and [1, 2, 3, 4]
// numbers is left alone

这么写不太好:

nestedNumbers = [[1], [2]];
numbersCopy = [...nestedNumbers];

numbersCopy[0].push(300);
console.log(nestedNumbers, numbersCopy);
// [[1, 300], [2]]
// [[1, 300], [2]]
// They've both been changed because they share references

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]
// numbers is left alone

这么写不太好:

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]]
// They've both been changed because they share references

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

for 循环类似——不太简洁,不够描述型......但是它总归也能用!

numbers = [1, 2, 3];
numbersCopy = [];
i = -1;

while (++i < numbers.length) {
  numbersCopy[i] = numbers[i];
}

注意:这也是通过 引用 而不是 来分配对象/数组。

这个写法很好:

numbersCopy.push(4);
console.log(numbers, numbersCopy);
// [1, 2, 3] and [1, 2, 3, 4]
// numbers is left alone

这么写不太好:

nestedNumbers = [[1], [2]];
numbersCopy = [];

i = -1;

while (++i < nestedNumbers.length) {
  numbersCopy[i] = nestedNumbers[i];
}

numbersCopy[0].push(300);
console.log(nestedNumbers, numbersCopy);
// [[1, 300], [2]]
// [[1, 300], [2]]
// They've both been changed because they share references

4、Array.map(浅拷贝)

回到现代领域,我们会发现 map 函数。映射起源于数学map  是在保留结构的同时将集合转换为另一种类型的集合的概念。

这意味着 Array.map 每次都会返回相同长度的数组。

要将数字列表加倍,请使用带有 double 函数的 map

numbers = [1, 2, 3];
double = (x) => x * 2;

numbers.map(double);

拷贝呢?

没错,本文是关于拷贝数组的。要复制数组,只需在 map 调用中返回元素即可。

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

如果你想更加数学化,(x) => x 被称为恒等,它返回给定的任何参数。

map(identity) 拷贝一个列表。

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

注意:这也是通过 引用 而不是 来分配对象/数组。

5、Array.filter(浅拷贝)

此函数会返回一个数组,就像 map 一样,但是不能保证长度相同。

如果你要过滤偶数,怎么办?

[1, 2, 3].filter((x) => x % 2 === 0);
// [2]

输入数组的长度为 3,但结果长度为 1。

但是,如果 filter 始终返回 true,则将获得重复项!

numbers = [1, 2, 3];
numbersCopy = numbers.filter(() => true);

每个元素都通过测试,因此会返回。

注意:这也是通过 引用 而不是 来分配对象/数组。

6、Array.reduce(浅拷贝)

我觉得使用 reduce 拷贝数组很糟糕,因为它的功能远不止于此。但是,我们试试看......

numbers = [1, 2, 3];

numbersCopy = numbers.reduce((newArray, element) => {
  newArray.push(element);

  return newArray;
}, []);

reduce 循环遍历列表时,转换初始值。

这里的初始值是一个空数组,我们将使用每个元素填充它。该数组必须从函数中返回,以在下一次迭代中使用。

注意:这也是通过 引用 而不是 来分配对象/数组。

7、Array.slice(浅拷贝)

slice 根据你提供的开始/结束索引返回数组的浅拷贝副本。

如果我们想得到前 3 个元素:

[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!

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(浅拷贝)

这可以将任何可迭代对象转换为数组。输入数组将返回浅拷贝。

numbers = [1, 2, 3];
numbersCopy = Array.from(numbers);
// [1, 2, 3]

注意:这也是通过 引用 而不是 来分配对象/数组。

总结

怎么样,有意思吧?

我尝试仅用一个步骤进行拷贝。如果你采用多种方法和技术,你将会发现更多。

原文:How to clone an array in JavaScript,作者:Yazeed Bzadough