发布于 2026-01-06 1 阅读
0

为什么在 JavaScript 中映射已构造的数组不起作用

为什么在 JavaScript 中映射已构造的数组不起作用

为什么在 JavaScript 中映射已构造的数组不起作用

以及如何正确操作

设想

为了演示,假设你需要生成一个从 0 到 99 的数字数组。你会怎么做呢?这里提供一种方法:

const arr = [];

for (let i = 0; i < 100; i++) {
  arr[i] = i;
}

如果你和我一样,看到 JavaScript 中传统的 for 循环会有点不习惯。事实上,多亏了forEachmapfilterreduce等高阶函数,我已经好几年没写过传统的 for 循环了。声明式函数式编程真是太棒了!

也许你还没完全领略到函数式编程的魅力,觉得上面的解决方案看起来已经很好了。从技术上讲,它确实没问题,但当你体验过高阶函数的魔力之后,你可能会想:“肯定 更好的方法。

我对这个问题的第一反应是:“我知道了!我创建一个长度为 100 的空数组,然后把索引映射到每个元素! ” JavaScript 允许你使用 Array 构造函数创建一个长度为n 的空数组,就像这样:

const arr = Array(100);

完美,对吧?我有一个长度为 100 的数组,现在我只需要将索引映射到每个元素即可。

const arr = Array(100).map((_, i) => i);

console.log(arr[0] === undefined); // true

搞什么鬼!?数组的第一个元素应该是0,但它实际上是undefined

解释

为了解释这个问题,我需要在这里说明一个重要的技术区别。在 JavaScript 内部,数组对象,以数字作为键。例如:

['a', 'b', 'c']

本质上等价于以下对象:

{
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
}

当你访问数组中索引为 0 的元素时,你实际上只是在访问一个键为 0 的对象属性。这一点很重要,因为当你把数组看作对象,并结合这些高阶函数的实现方式(别担心,我已经帮你解释清楚了),我们遇到的问题的原因就完全说得通了。

使用 Array 构造函数创建新数组时,它会创建一个新的数组对象,并将length属性设置为您传入的值,但除此之外,该对象是空的。数组的对象表示中没有任何索引键。

{
  //no index keys!
  length: 100
}

当你尝试访问索引 0 处的数组值时,你会得到undefined,但这并不是因为undefined值存储在索引 0 处,而是因为 JavaScript 的默认行为是,如果你尝试访问对象中不存在的键的值,则返回undefined 。

恰好,高阶函数mapreducefilterforEach会遍历数组对象从 0 到length的所有索引键,但回调函数只有在键存在于对象中时才会执行。这就解释了为什么我们的回调函数永远不会被调用,以及为什么当我们对数组调用 map 函数时没有任何反应——因为根本没有索引键!

解决方案

如你所知,我们需要的是一个数组,其内部对象表示包含从 0 到length 的每个数字对应的键。实现这一点的最佳方法是将数组展开成一个空数组。

const arr = [...Array(100)].map((_, i) => i);

console.log(arr[0]);
// 0

将数组展开成一个空数组,得到的数组中每个索引处都填充了undefined

{
  0: undefined,
  1: undefined,
  2: undefined,
  ...
  99: undefined,
  length: 100
}

这是因为扩展运算符比 map 函数更简单。它只是简单地遍历数组(或者任何可迭代对象),从 0 到length,并在包含它的数组中创建一个新的索引键,其值为扩展数组在当前索引处的返回值。由于 JavaScript 默认会从扩展数组的每个索引处返回undefined(记住,这是因为它没有该值对应的索引键),最终我们会得到一个实际上填充了索引键的新数组,因此可以进行map操作(也可以进行reducefilterforEach操作)。

结论

我们发现了在 JavaScript 中将数组内部表示为对象的一些影响,并学习了创建任意长度数组并填充所需值的最佳方法。

和往常一样,请在下方留言、提问和反馈!

祝您编程愉快!👍

跟我来!

如果你喜欢这篇文章,请关注我!或者至少给我鼓掌一两下。哪怕只是轻轻鼓掌,你也能给点赞吧?

Medium@ shawn.webdev
Twitter@ReisnerShawn
dev.to:@sreisner Instagram @ shawn.webdev

查看我的更多作品


文章来源:https://dev.to/sreisner/heres-why-mapping-a-constructed-array-in-javascript-doesnt-work-55di