> arr = [];
> arr[100] = 1;
> The length will be 101, which makes sense due to 0-99 being set as undefined
该数组在 100 处只有一个成员,就像:
var arr = { '100': 1, 'length': 101};
现在,如果我们对该数组进行排序: arr.sort() 它将如下所示: [1, undefined x100]
不,它没有。它有一个成员为 0,长度为 100。没有 100 个成员的值为“未定义”。
如果您希望将数组减少为仅定义的成员,则没有内置函数可以做到这一点(即本质上将长度设置为具有值的最高索引)。
您只能通过遍历数组来做到这一点,例如通过从右边减少长度直到达到现有属性:
function trimArray(arr) {
var i = arr.length;
while ( !(--i in arr)) {
arr.length -= 1;
}
}
请注意,要使上述内容正常工作,必须对数组进行排序。此外,它会修改传入的数组。
这是一种使用 compress 方法扩展 Array.prototype 的方法,因此仅存在已定义成员的数组并且长度被适当地重置:
if (!('compress' in Array.prototype)) {
Array.prototype.compress = function() {
var i = 0,
lastExisting = 0,
len = this.length;
do {
if (i in this) {
this[lastExisting++] = this[i];
}
} while (++i < len)
this.length = lastExisting;
}
}
请注意,它不会删除值为undefined的成员,只会删除那些根本不存在的成员。所以:
var x = [,,,,1,,,2];
x[20] = void 0;
x.compress()
alert(x + '\n' + x.length); // [1,2,<undefined>], length = 3
编辑
正如 zzzzBov 所指出的,这也可以使用filter
:
var x = x.filter(function(item){return true;});
它将替换x
为仅包含已定义成员的新数组,而不管其值如何。它将是非稀疏的(或连续的)并且具有适当的长度,例如
var x = [,,,,1,,,2];
x[20] = void 0; // set x[20] to undefined, length is 21
x = x.filter(function(item){return true;}); // [2, 3, <undefined>], length = 3
请注意,此方法只会更新 x 引用的数组,不会更新对同一数组的任何其他引用,例如
var x = [,,1];
var y = x; // x and y reference same array
x = x.filter(function(item){return true}); // x is now another array of members
// filtered from the original array
alert(x); // [1] x references a different array
alert(y); // [,,1] y still references the original array
如果需要保留原始数组,这可能是有用的行为。相反,该compress
方法修改了原始数组:
var x = [,,1];
var y = x; // x and y reference same array
x.compress();
alert(x); // [1] x is a modified version of the original array
alert(y); // [1] y references the same (original) array
我不知道是否打算Array.prototype
在未来版本的 ECMAScript 中添加这样的方法或它可能被称为什么,因此可能建议使用不同的名称,比如xcompress
或类似的名称,以避免与未来版本发生意外冲突并使其成为可能很明显,这是一种本机方法,而不是内置方法。
对于合适的名称,我也有点难过,因为packed和compressed已经定义了与non-contiguous不同的含义,但这看起来很笨拙,所以现在是compress。