2

如果您使用数组并执行以下操作:

arr = [];
arr[100] = 1;

长度为 101,这是有道理的,因为 0-99 被设置为undefined

现在,如果我们对该数组进行排序:arr.sort()它看起来像这样:[1, undefined x100]因为没有保留键。但是,长度仍然是 101,因为undefined已经全部移到末尾,而不是删除。

这种行为是故意的吗?如果是这样:是否有一个内置函数可以删除undefined和重新计算,为什么是故意的?

不是在问如何编写自己的函数来重新计算长度。排序数组的长度可以很容易地强制使用for (x = 0; arr[x] != undefined; x++);arr.length = x;

4

3 回答 3

5
> 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或类似的名称,以避免与未来版本发生意外冲突并使其成为可能很明显,这是一种本机方法,而不是内置方法。

对于合适的名称,我也有点难过,因为packedcompressed已经定义了与non-contiguous不同的含义,但这看起来很笨拙,所以现在是compress

于 2012-09-13T03:26:22.887 回答
1
arr = [];
arr[100] = 1;

代码不会设置0-99undefined,它只是将键设置1001,并将length属性设置为101

并且Array.sort不会改变length数组的属性。

排序后,有两个自己的属性arr01length还是仍然101

在此处输入图像描述

于 2012-09-13T03:32:40.237 回答
0

如果您想解决该问题,filter请在对数组进行排序后(或在排序前对其进行过滤)。

var arr;
arr = [];
arr[100] = 1;
arr.sort();
arr = arr.filter(function (item) {
    return typeof item !== 'undefined';
});

实际发生的情况是您正在覆盖length属性,对象使用该Array属性来确定数组的末尾在哪里,数组是否具有那么多属性。

于 2012-09-13T03:27:23.917 回答