返回
解剖 ES6 数组 fill() 填充的陷阱:为什么它会导致意外的二维数组?
前端
2023-09-13 16:42:07
在 JavaScript 的世界里,数组作为一种强大的数据结构,承载着我们应用程序的关键信息。ES6 为数组提供了便捷的 fill()
方法,允许我们轻松地用特定值填充数组。然而,在使用 fill()
时,一个看似简单的任务却可能导致一个出人意料的陷阱:二维数组的意外生成。
场景再现
让我们从一个看似直观的场景开始。假设我们想将一维数组转换成二维数组。于是,我们愉快地编写了以下代码:
const oneDimArray = [1, 2, 3];
const twoDimArray = new Array(3).fill(oneDimArray);
console.log(twoDimArray);
我们期望输出如下结果:
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
但结果却是令人震惊的:
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
咦,为什么每个内数组都指向同一个引用?让我们深入剖析一下问题所在。
填充过程的秘密
fill()
方法有两个主要参数:要填充的值和可选的开始和结束索引。当没有提供开始和结束索引时,fill()
会从头到尾填充整个数组。在我们的案例中,new Array(3)
创建了一个长度为 3 的新数组,然后用 oneDimArray
填充。
乍一看,这个过程似乎没有什么问题。然而,关键在于 fill()
如何处理填充值。它不复制填充值,而是直接使用对填充值的引用。这正是导致意外行为的原因。
当我们用 oneDimArray
填充新数组时,每个元素都是 oneDimArray
本身的引用。这意味着当我们修改新数组中的任何元素时,原始 oneDimArray
也会受到影响。
陷阱的解决方案
要避免这个陷阱,我们需要确保填充值是原始值的副本。有几种方法可以做到这一点:
- 使用扩展运算符(...):
let twoDimArray = new Array(3).fill([...oneDimArray]);
- 使用
slice()
方法:let twoDimArray = new Array(3).fill(oneDimArray.slice());
- 使用
map()
方法:let twoDimArray = new Array(3).fill(oneDimArray.map(x => x));
这些方法都会创建 oneDimArray
的副本,从而避免意外的二维数组行为。
结论
ES6 数组的 fill()
方法是一个强大的工具,但它潜藏着填充值引用的陷阱。通过理解这一机制并采用适当的复制策略,我们可以避免意外行为并编写健壮可靠的代码。