4

我有一个数组,我只想删除一个元素,但不重新排序键。有没有不使用删除或重建整个数组的简单方法?

或者在删除后清理以摆脱未定义的值,再次固定长度。

var array = ["valueone", "valuetwo"];

console.dir(array); // keys 0 and 1
array.splice(0, 1);
console.dir(array); // key 1 is now 0, do not want!
4

3 回答 3

7

您可以delete将数组的元素:

a = ['one', 'two'];
delete a[0];

// a is now [undefined, 'two'];

或者,a[0]明确设置为undefined.

请注意,数组.length参数由系统自动维护。如果您故意将其设置为更高的数字,您将获得大量undefined缺失键的值:

a.length = 10;
// a is now [undefined, 'two', undefined x 8]

如果您不能接受这些语义,那么您应该考虑使用 anObject来代替。这将保留您的密钥,也许效率更高,但您会失去.length财产。

于 2013-03-05T21:54:13.453 回答
2

您不能直接将值显式设置为 undefined 或 null 或空字符串。你想达到什么目的?

var arr = ['aaaa','bbb','ccc','ddd'];
    arr[0]= undefined;
    //or
    arr[0]= null;
    ///or
    arr[0]= "";
    arr.length; <--- 4
于 2013-03-05T22:00:57.647 回答
1

2018-09-07 更新

在我看来,这个答案不是很好。我提供了一个关于如何从 JavaScript 对象中删除属性的答案,这些年来我受到了更多的关注,并涵盖了这个案例并进行了更详细的介绍。

关键是,您应该使用Array.prototype.spliceand Array.prototype.slice

array.splice(start, n)返回具有顺序元素的arrayfrom index的子集,并从原始数组中删除此子集,在此过程中创建一个新数组。startn

let array = [1,2,3,4,5,6];
array.splice(2,3); // [3,4,5]
array; // [1,2,6]

array.slice(start, end)返回array从索引start到索引的子集,end而不改变原始索引。行为与 有点不同splice,这就是为什么我更喜欢将其称为array.slice(start, start + n)

let array = [1,2,3,4,5,6];
array.slice(2, 2 + 3); // [3,4,5]
array; // [1,2,3,4,5,6]

当然,您可以将索引设置为类似nullor的标记值"",但如果您希望数组在删除后保持相同的顺序,也许您应该改变您的方法——为什么"valuetwo"必须在索引 1 处?如果内容总是与访问它们所需的密钥相同,那么这个数据结构中甚至保存了哪些有用的信息?


原答案如下。如果我要保留原文,也许我应该详细说明为什么这是不好的建议。

您可以使用 javascript 的delete关键字。

delete array[index];

不要这样做。如果你的数组是同质的(应该是这样的),那么这将通过引入第二种类型(undefined)来破坏你的数组。您应该array.splice()如上所述使用,这将创建一个省略指定范围的新数组。

不幸的是,这会undefined在数组内部创建一个索引

var arr = ['pie', 'cake', 'fish'];
delete arr[1];
arr; // ['pie', undefined, 'fish']

举个例子。

你也可以这样做:

var arr = [9,8,7,6];
arr[1] = null;
arr;        // [9,null,7,6]
arr.length; // 4
var i = -1;
while(++i < arr.length){
    if(arr[i] && typeof(arr[i] === "number")){
        alert(arr[i]);
    }
}

你可以,但你不应该。这不仅是不必要的,而且没有做任何有用的事情(因为它所做的只是调用alert),而且它实际上已经被破坏了。

if(arr[i] && typeof(arr[i] === "number")){
    alert(arr[i]);
}

你可能希望它只打印我们的元素,如果它是一个非零数字,但实际上也会运行类似的值"foo"[]document.createElement("p"),因为typeof(arr[i] === "number")总是返回值"boolean",它是一个非空字符串,它是真实的并且会因此评估为真。alert这意味着被调用的唯一要求arr[i]是真实的。整个语言中只有六个值会导致这个 if 语句不执行,它们是:

  • undefined
  • null
  • 0
  • ""(读作“空字符串”)
  • false
  • NaN

或者,如果您不需要使用数组,则可以使用对象并使一切变得更容易:

var obj = {
    0: "first",
    1: "second",
    2: "third"
};
delete obj[1];
obj; // {0: "first", 2: "third"}
for(var i in obj){
    alert(obj[i]);
}

这将立即消除使用数组的所有优势。现在你有一个数据集,它可能是异构的,也可能不是异构的,它不能以任何理智的方式过滤、映射、减少或转换,你必须求助于类似的东西for(i in obj)(如果你敢这样做的话,这是极容易出错的使用像 jQuery 这样的库)来迭代它。幸运的是,今天我们有一些花哨的东西,例如Object.keys(obj).map(k => obj[k]).forEach(function(el){ ... }),但这不是拥有糟糕数据结构的借口。

要获取对象的长度:

getLength = function(obj){
    var i = 0, l = 0;
    for(i in obj){
        l++;
    }
    return l;
}
getLength(obj); // 3

同样,对于数组,这是不必要的。

但请记住,对象date of creation按名称对索引进行排序,而不是 >。不过,这不应该导致障碍。

要按字母顺序对对象的索引进行排序:

sortObject = function (){
    var arr = [], i;
    for(i in this){
        arr.push({index:i,content:this[i]});
        delete this[i];
    }
    arr.sort();
    for(i in arr){
        var item = arr[i];
        this[item.index] = item.content;
    }
    return this; // make chainable
}
var obj = {
    acronym: "OOP",
    definition: "Object-Oriented Programming",
    article: "http://wikipedia.org/OOP"
};
sortObject.apply(obj); // indices are "acronym", "article", "definition"
array.sort(fn)

无论如何,对象的全部意义在于它的属性是未排序的。对未排序的列表进行排序几乎不会做任何有用的事情。

只是为了说明数组在做数组事情方面有多好:

let array = ["pie", "cake", "fish", "brownie", "beef", ...];
/* do some stuff... */
array
.filter(el => exclude.indexOf(el) === -1)
.forEach(function(el){
    console.log(el);
});

如果exclude["cake", "brownie"],那么这会将以下内容记录到控制台:

pie
fish
beef
...

试想一下使用此答案的先前版本中的方法来执行相同操作需要多少不必要的代码行。


希望这有帮助

希望此更新有所帮助。

于 2013-03-05T22:47:42.393 回答