JavaScript数组初始化的多种方式
在JavaScript中初始化数组是一项关键任务,有许多可供选择的技术和需要考虑的性能问题。虽然可能没有一种适用于所有情况的解决方案,但有几个选项值得考虑。
Array() 构造函数
你可能首先会想到的是使用 Array()
构造函数。令人意外的是,这可能是单独使用时最有问题的选项。虽然它可以用于创建具有给定值的数组的任意数量的参数,但在其他方面它的功能相对有限。它的大部分问题都源于生成的数组中的空洞或“空”值以及如何处理这些值。
const arr = Array(3); // [ , , ] - 3个空槽
arr.map(() => 1); // [ , , ] - map() 跳过空槽
arr.map((_, i) => i); // [ , , ] - map() 跳过空槽
arr[0]; // undefined - 实际上,它是一个空槽
Array.from()
Array.from()
是一个静态方法,它从一个类数组对象或可迭代对象创建一个新的浅拷贝的数组实例。它非常适用于将类数组对象(例如 arguments
,NodeList
)或可迭代对象(例如 Set
,Map
,Generator
)转换为实际的数组。除此之外,通过传递一个具有 length
属性的对象,它可以轻松地“欺骗”成创建指定长度的数组。这种方法有点慢,但它运行良好并且可以避免 Array()
构造函数的一些问题。此外,它允许你传递一个映射函数作为第二个参数,这对于使用值初始化数组非常有用。
const arr = Array.from({ length: 3 }); // [undefined, undefined, undefined]
arr.map(() => 1); // [1, 1, 1]
arr.map((_, i) => i); // [0, 1, 2]
const staticArr = Array.from({ length: 3 }, () => 1); // [1, 1, 1]
const indexArr = Array.from({ length: 3 }, (_, i) => i); // [0, 1, 2]
Array.prototype.fill()
虽然 Array.from()
非常灵活,但使用映射函数填充相同的值并不特别高效。Array.prototype.fill()
可以填充现有数组,以相同的值填充数组。这在与 Array()
构造函数结合使用时也很方便,因为它允许你用一个值填充数组,而不是空槽。
const nullArr = new Array(3).fill(null); // [null, null, null]
const staticArr = Array.from({ length: 3 }).fill(1); // [1, 1, 1]
const indexArr = Array(3).fill(null).map((_, i) => i); // [0, 1, 2]
Array.prototype.map()
Array.from()
允许通过第二个参数传入一个映射函数,但很多人认为这样写不够清晰易读。此外,在一些特殊情况下,能够在映射过程中访问数组本身可能会很有用。如果你关心代码的灵活性和可读性,Array.prototype.map()
提供了这一点额外的灵活性和可读性。它也能够完成你可能需要的几乎所有其他操作,但请记住它不能很好地处理空值。
const arr = Array(3).map(() => 1); // [ , , ] - map()跳过空槽
const staticArr = Array.from({ length: 3 }).map(() => 1); // [1, 1, 1]
const indexArr = Array.from({ length: 3 }).map((_, i) => i); // [0, 1, 2]
const fractionArr =
Array.from({ length: 3 }).map((_, i, a) => i / a.length); // [0, 0.5, 1]
关于性能的注意事项
如果在你的应用程序中这种操作非常常见,性能可能是一个问题,但总体来说,这些选项都不是特别慢。Array()
构造函数似乎是最快的。也就是说,如果与Array.prototype.fill()
结合使用,它可以是用单个值初始化数组的最佳选项。奇怪的是,即使在之后链式调用Array.prototype.map()
来创建动态值,这种性能优势仍然存在。因此,我的个人建议如下:
const initializeArrayWithValues = (n, val = 0) => Array(n).fill(val);
const initializeMappedArray = (n, mapFn = (_, i) => i) =>
Array(n).fill(null).map(mapFn);
initializeArrayWithValues(4, 2); // [2, 2, 2, 2]
initializeMappedArray(4, (_, i) => i * 2); // [0, 2, 4, 6]
你可以在这个集合中了解更多与JavaScript数组初始化相关的技巧和技巧。