flatMap异常:为何new Array(1)映射生成的数组无法被展平导致测试失败
异常根因拆解
核心前置概念:稀疏数组(空槽数组)
JS里通过new Array(length)生成的数组是稀疏数组,和手动赋值的稠密数组有本质区别:
- 稀疏数组对应长度的索引位置不存在实际的属性键,也就是常说的“空槽(hole)”,并非在槽位上存储了
undefined值,而是完全没有对应索引的属性定义 - 访问空槽位置的元素时,会因为找不到对应属性返回
undefined,但这个返回值不是数组存储的内容 - 可以用
in运算符做差异验证:const sparseArr = new Array(1); console.log(0 in sparseArr); // 输出false,索引0不存在 const denseArr = [undefined]; console.log(0 in denseArr); // 输出true,索引0存在,值为undefined
关联数组方法的遍历规则
两个数组方法的内置实现逻辑,是导致测试失败的直接原因:
Array.map()的执行规则
map方法遍历数组时,只会对自身存在有效属性的索引执行回调,遇到空槽会直接跳过,且返回的新数组会完整保留原数组的所有空槽位置。
这也解释了第一个测试用例的表现:new Array(1).map(() => "x")根本没有执行回调里的赋值逻辑,返回的数组依然是长度为1的稀疏数组,索引0位置是空槽,访问取值自然是undefined。常见认知误区:很多开发者误以为
new Array(n).map(回调)会按照传入的回调把每个槽位填上值,实际上因为空槽会被map直接跳过,回调根本不会执行,返回的数组和原数组一样是带空槽的稀疏数组,不会填充任何值。如果要生成带实际值的稠密数组,需要用Array.from({length:1}, ()=>"x")或者new Array(1).fill("x")。Array.flatMap()的执行规则
flatMap的完整执行逻辑是:先遍历外层数组执行映射回调,再把每个回调的返回值做1层深度的扁平化,最终拼接为结果数组。在扁平化展开的过程中,和map的逻辑一致——会直接跳过被展开数组里的所有空槽,不会把空槽计入最终结果。
第三个测试用例的完整执行路径
- 外层数组
[undefined]是稠密数组,索引0位置是有效属性,flatMap会正常执行传入的回调 - 回调返回的是
new Array(1).map(() => "x"),也就是前面提到的长度为1的稀疏数组,索引0位置是空槽 - flatMap开始对这个返回的稀疏数组做扁平化展开,遍历到索引0位置发现是空槽,直接跳过,没有任何值被追加到结果数组
- 最终得到的结果是空数组,长度为0,自然触发断言失败
第二个测试用例的通过原因
第二个用例里回调返回的是稠密数组[undefined],索引0位置是真实存储的undefined值,flatMap扁平化时会完整保留这个有效值,因此结果数组长度为1,能正常取到undefined值。
内容的提问来源于stack exchange,提问作者Smartkid
相关产品推荐
相关产品推荐

