为什么在 JavaScript 中映射已构造的数组不起作用
为什么在 JavaScript 中映射已构造的数组不起作用
以及如何正确操作
设想
为了演示,假设你需要生成一个从 0 到 99 的数字数组。你会怎么做呢?这里提供一种方法:
const arr = [];
for (let i = 0; i < 100; i++) {
arr[i] = i;
}
如果你和我一样,看到 JavaScript 中传统的 for 循环会有点不习惯。事实上,多亏了forEach、map、filter和reduce等高阶函数,我已经好几年没写过传统的 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 。
恰好,高阶函数map、reduce、filter和forEach会遍历数组对象从 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操作(也可以进行reduce、filter和forEach操作)。
结论
我们发现了在 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
