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

Rhy*_*ono 2 javascript google-chrome

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

arr = [];
arr[100] = 1;
Run Code Online (Sandbox Code Playgroud)

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

现在,如果我们对该数组进行排序:arr.sort()它将如下所示:[1, undefined x100]因为不保留键.然而,长度仍然是101,因为undefined已经全部移动到最后,而不是删除.

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

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

Rob*_*obG 5

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

> The length will be 101, which makes sense due to 0-99 being set as undefined
Run Code Online (Sandbox Code Playgroud)

该数组在100只有一个成员,它就像:

var arr = { '100': 1, 'length': 101};
Run Code Online (Sandbox Code Playgroud)

现在,如果我们对该数组进行排序:arr.sort()它将如下所示:[1,undefined x100]

不,它没有.它有一个成员为0,长度为100.没有100个成员的值为'undefined'.

如果您希望将数组简化为仅定义的成员,则没有内置函数来执行此操作(即基本上将长度设置为具有值的最高索引).

你只能通过遍历数组来做到这一点,例如通过从右边减少长度直到达到现有属性:

function trimArray(arr) {
  var i = arr.length;
  while ( !(--i in arr)) {
    arr.length -= 1;
  } 
}    
Run Code Online (Sandbox Code Playgroud)

请注意,要使上述方法正常工作,必须对数组进行排序.此外,它修改传入的数组.

这是一种使用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; 
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,它不会删除其值未定义的成员,只会删除那些根本不存在的成员.所以:

var x = [,,,,1,,,2];
x[20] = void 0;

x.compress()

alert(x + '\n' + x.length); // [1,2,<undefined>], length = 3
Run Code Online (Sandbox Code Playgroud)

编辑

正如zzzzBov所指出的,这也可以使用filter:

var x = x.filter(function(item){return true;});
Run Code Online (Sandbox Code Playgroud)

它将替换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
Run Code Online (Sandbox Code Playgroud)

请注意,此方法仅更新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
Run Code Online (Sandbox Code Playgroud)

如果需要保留原始数组,这可能是有用的行为.相反,该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
Run Code Online (Sandbox Code Playgroud)

我不知道是否有意Array.prototype在ECMAScript的未来版本中添加这样的方法或者它可能被调用的内容,因此可能建议使用不同的名称,例如xcompress或类似,以避免与未来版本的意外冲突并使其成为可能.很明显,这是一种本地方法,而不是内置方法.

我也有点难以找到一个合适的名字,因为打包压缩已经定义了与非连续不同的含义,但这看起来很笨重所以它现在是压缩的.

  • @Rhyono请记住,JavaScript中的"数组"与Java或C中的数组不同. (2认同)