Javascript 排序后强制数组重新计算长度

Javascript 排序后强制数组重新计算长度,javascript,google-chrome,Javascript,Google Chrome,如果使用数组并执行以下操作: arr = []; arr[100] = 1; 长度将为101,这是有意义的,因为0-99被设置为undefined 现在,如果我们对该数组进行排序:arr.sort()它将如下所示:[1,未定义的x100],因为键不会被保留。但是,长度仍然是101,因为未定义的已全部移到末尾,而不是移除 这种行为是故意的吗?如果是这样的话:是否有一个内置函数可以删除未定义的并重新计算,为什么是故意的 我不是问如何编写自己的函数来重新计算长度。排序数组的长度可以很容易地通过for

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

arr = [];
arr[100] = 1;
长度将为101,这是有意义的,因为0-99被设置为
undefined

现在,如果我们对该数组进行排序:
arr.sort()
它将如下所示:
[1,未定义的x100]
,因为键不会被保留。但是,长度仍然是101,因为
未定义的
已全部移到末尾,而不是移除

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

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

> 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,未定义x100]

不,没有。它在0处有一个成员,长度为100。没有100个成员的值为“undefined”

如果希望将数组缩减为仅定义的成员,则没有内置函数来完成此操作(即,本质上是将长度设置为具有值的最高索引)

只能通过在数组上迭代来实现,例如,从右边开始减少长度,直到达到现有属性为止:

function trimArray(arr) {
  var i = arr.length;
  while ( !(--i in arr)) {
    arr.length -= 1;
  } 
}    
请注意,要使上述操作正常工作,必须对数组进行排序。此外,它还修改传入的数组

下面是一种使用压缩方法扩展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; 
  }
}
它将用只包含已定义成员的新数组替换
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
如果需要保留原始阵列,这可能是有用的行为。相反,
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
我不知道是否有人打算在未来版本的ECMAScript中将这种方法添加到
Array.prototype
,或者它可能被称为什么,因此建议使用不同的名称,例如
xcompress
或类似名称,以避免与未来版本发生意外冲突,并使其明显表明它是本机方法,不是内置的


我也有点难以找到一个合适的名称,因为packed和compressed已经定义了不同于non-continuous的含义,但这似乎很难理解,所以现在它是compressed。

如果您想解决这个问题,请在对数组进行排序(或在排序之前对其进行过滤)后立即使用它

实际发生的是,您正在重写
length
属性,该属性由
Array
对象用于确定数组的结尾位置,以及数组是否有那么多属性

arr = [];
arr[100] = 1;
代码不会将
0-99
设置为
undefined
,它只会将键
100
设置为
1
,将
length
属性设置为
101

Array.sort
不会更改数组的属性
length

排序后,有两个自己的属性
arr
0
1
length
仍然是
101


为什么排序会删除元素?@DaveNewton因为排序承认元素没有定义,为什么要保留它们?排序后是否可以应用其他函数来删除它们?如果您有一个给定长度的数组,并对其进行排序,我不理解如果长度不同,则返回一些内容的想法。@Rhyono最后的函数将删除值为
null
未定义的成员(即,它们的值为
undefined
)。我使用的是Chrome(根据标签)和开发者控制台:以下是数组
[1,10,10,2,undefined×96]
@Rhyono的确切输出,这是由于开发者控制台显示数组数据的方式。如果使用
arr.hasOwnProperty(10)
您应该得到
false
,因为它实际上没有设置该属性。@Rhyono记住,JavaScript中的“数组”与Java或C中的数组不同。@zzzzBov这就是我要找的。这也是我特别说“chrome”的原因在标记中,因为它实际上没有意义将所有这些定义为未定义的,但因为它只是它表示它的方式:这是可以理解的。@Rhyono,firefox中的firebug还显示了许多未定义的
列表,因为未设置的属性将返回
未定义的
(例如
a={};a[100];//未定义的
)。这不是OP要求的。他们声明他们已经知道如何执行上述操作。@zzzzBov函数应该是
var y=x.filter(函数(项){return item;});
因为只访问存在的成员。您的函数将删除值为
未定义的现有成员@RobG,不确定您引用的是什么API,但是。如果使用
返回项;
,将从数组中删除假值。@zzzzBov是的,您是对的。筛选函数应返回
真值以便保留所有已定义的属性(包括那些具有虚假值的属性,例如
未定义的
虚假的
0
,等等)。如果长度不超过100,则表示它的方式会有所不同。这让我很反感。
 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
 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
var arr;
arr = [];
arr[100] = 1;
arr.sort();
arr = arr.filter(function (item) {
    return typeof item !== 'undefined';
});
arr = [];
arr[100] = 1;