JavaScript 数组:如何压缩多余的长度?

JavaScript arrays: how do I compact excess length?

这可能看起来像一个重复的问题,但请不要仅仅因为它看起来与其他问题相似就假设它,并且除非您真正理解其后果,否则请谨慎回答简单的答案。

这是一个演示问题的控制台对话框:

> a = [0,1,2]
< >(3) [0,1,2]
> a.length
< 3
> a[99] = 99
< 99
> a.length
< 100
> delete a[99]
< true
> a.length
< 99

所以这个长度 属性 的数组似乎没有遵循任何合理的规范。应该压缩尾随的稀疏元素,但实际上没有。

因此,我认为长度 属性 永远不应在代码中使用,因为它在语义上毫无意义。 (相反,findLastIndex(() => true) 应该用于天真的程序员以前使用 length 的任何地方。)

我知道如何使用优雅的 forEach、some、every、find、filter、map 和 reduce 函数。而且我知道过滤器不会保留稀疏性。我可以使用 reduce 做一个可以删除元素的地图或一​​个保留稀疏性的过滤器。

如何在不复制数组的情况下将数组长度属性重置为合理的值?

可能根本没有答案,或者更确切地说,答案可能是“没有办法,数组长度属性本质上没有意义。”

由于JavaScript规范中没有说length必须正好比上一个索引高1,所以你的要求是不合理的。通常情况下,密集数组的数量远远超过稀疏数组。由于 JavaScript 不会将索引保持在有序结构中,因此在不需要这种更强的不变量的许多情况下,每次数组内容更改时找出最后一个索引会导致性能损失。

如果您确实需要 trim 向下排列数组以排除尾随 non-elements,这很容易做到:找到最后一个有效索引,然后自己收缩数组:

const a = [0,1,2]
a[99] = 99
delete a[99]
a.length = a.findLastIndex(i => i in a) + 1;
console.log(a);        // [1, 2, 3]
console.log(a.length); // 3

万一length很大,能慢点吗?是的。这正是默认情况下不进行此计算的原因。

编辑:findLastIndex 并非在所有浏览器中都存在,可能需要解决方法或 polyfill。

EDIT2:更好的是,可以使用 reduce,它不会为不存在的索引调用谓词(并且也存在于所有当前的浏览器中):

const a = [0,1,2]
a[99] = 99
delete a[99]
a.length = a.reduce((l, x, i) => i, 0) + 1;
console.log(a);        // [1, 2, 3]
console.log(a.length); // 3