【问题标题】:Why does the array still have a non-zero length after deletion?为什么删除后数组仍然有非零长度?
【发布时间】:2013-08-23 06:56:24
【问题描述】:

我有以下代码输出数组的长度,删除它,然后输出新的长度:

console.log($scope.adviceList.activeAdvices.length); // *1*
$scope.adviceList.activeAdvices.splice(id,1); // *id is a parameter*
console.log($scope.adviceList.activeAdvices.length); // *0*

console.log($scope.adviceList.activeAdvices.length); // *1*
delete $scope.adviceList.activeAdvices[id];
console.log($scope.adviceList.activeAdvices.length); // *0*
console.log($scope.adviceList.activeAdvices); // *[]*

删除后,数组正确显示为空。但是,它的长度仍然是 1。

【问题讨论】:

标签: javascript arrays


【解决方案1】:

delete 是“低级”运算符。它直接作用于对象,它不“知道”数组。使用delete 根本不会触发例程重新计算数组长度。


这里的其他答案声称该属性的值设置为undfined,这是不正确的。一个简单的测试表明:

var a = [1]; 
delete a[0]; 
console.dir(a);

比较一下如果你真的将值设置为undefined会发生什么:

var a = [1]; 
a[0] = undefined; 
console.dir(a);

为了更可靠的证据,让我们看看specification

O 的 [[Delete]] 内部方法以属性名称 P 和布尔标志 Throw 调用时,以下步骤采取:

  1. desc 为调用属性名为 PO 的 [[GetOwnProperty]] 内部方法的结果。
  2. 如果 desc 未定义,则返回 true
  3. 如果 desc.[[Configurable]] 为 true,则
    一种。从 O 中删除名称为 P 的自己的属性。
    湾。返回 true
  4. Else if Throw,然后抛出 TypeError 异常。
  5. 返回 false

没有地方说属性的值设置为undefined


不同浏览器的控制台可能会显示不同的数组表示。在这个特定的例子中,你可以争论它应该是[] 还是[undefined]

  • [] (Chrome) 似乎很有意义,因为该数组确实没有任何元素,也没有带有数字名称的属性。但是,当您访问 .length 属性时,您会得到一个 1,这可能会造成混淆。
    不久前,Chrome 使用a representation like [undefined x 5] 表示一个长度为 5 但没有元素的数组。我认为这实际上是一个很好的解决方案。

  • [undefined] (Firefox) 有意义,因为数组的长度为 1,访问 arr[0] 实际上返回 undefined(但 arr[10] 也是如此)。但是,arr.hasOwnProperty(0) 将是 false如果一个数组确实包含值undefined,如何仅通过这种表示将它与长度为1的空数组区分开来(答案:你不能)。

底线是:不要太相信console.log。如果您想要精确的表示,请使用console.dir

【讨论】:

  • 那是我写的,你为什么要对我投反对票,delete 之后的数组对象的解释是[ undefined ]
  • @Antti:是什么让你认为我对你投了反对票?我没有。正如我已经评论过的,我对您的控制台输出 ([ undefined ]) 感到困惑,并在没有彻底阅读您的答案的情况下得出结论,这就是我发表评论的原因。但是,我没有投反对票。
  • 让我更加困惑的一件事是,MDN 说 undefined 和 no 属性对于 forEach 的行为方式都应该相同,但即使在 Firefox 上它们也不会有行为
  • 我的说未定义,Chrome。
  • @johnny:访问一个不存在的属性将返回undefined。这与将属性设置为 undefined 不同(正如我在答案中演示的那样)。
【解决方案2】:

这是因为数组元素上的删除将其设置为未定义,因此长度不会改变。请改用splice 函数:

a = [1,2,3,4];
a.splice(2,1);
console.log(a.length);

【讨论】:

  • 简单有效
【解决方案3】:

如果你想“删除”数组中的一个项目,你可以

var a = ["a","b"];
console.log(a);  //a,b
console.log(a.length);//2
a.length = 1;//"delete" all greater than length 1 of items;
console.log(a);//a
console.log(a.length);//1

 var a = ["a","b"];
    console.log(a);  //a,b
    console.log(a.length);//2
    a.pop();//"delete" the last in array:"b"
    console.log(a);//a
    console.log(a.length);//1

 var a = ["a","b"];
    console.log(a);  //a,b
    console.log(a.length);//2
    a.shift();//"delete" the first in array:"a"
    console.log(a);//b
    console.log(a.length);//1

 var a = ["a","b"];
    console.log(a);  //a,b
    console.log(a.length);//2
    a.splice(1,1);//"delete" from index 1(include,first parameter),delete number is 1(second parameter)
    console.log(a);//a
    console.log(a.length);//1

【讨论】:

    【解决方案4】:

    就我而言,我重新定义了删除后的长度:

    var cars = ["BMW", "Volvo", "Saab", "Ford"];
    delete cars[1];
    
    /// 1st option ///
    for (var i = 0; i < cars.length; i++){
      if(i in cars)
        document.write(cars[i] + " ");
    }
    /// return: BMW Saab Ford
    
    /// 2nd option ///
    cars.length--;
    var realLength = cars.length;
    

    【讨论】:

      【解决方案5】:

      我创建了一个新数组并在其上添加了pushed 元素以获得正确的长度。例如,我有这个表头:

       var finalTableHeaderArray = [];
      
       tableHeaderArray.forEach(function (element, index, array) {
          if (removeDisplayItems.indexOf(index) === -1)
              finalTableHeaderArray.push(element);
       }, self);
      

      不完全是您的问题,但它可以帮助其他人。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-04-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-26
        • 2018-06-25
        相关资源
        最近更新 更多