如何从JavaScript关联数组中删除对象?

719

假设我有以下代码:

var myArray = new Object();
myArray["firstname"] = "Bob";
myArray["lastname"] = "Smith";
myArray["age"] = 25;

现在如果我想要移除 "lastname" ,是否有类似于 myArray["lastname"].remove() 的等效方法呢?(我需要移除此元素,因为元素的数量很重要,我想保持数据干净)


33
提示:不要混淆数组和映射。有些语言(如PHP)将两者都归为单个对象。虽然您在此处使用了正确的类型(new Object()),但是您将其命名为myArray,这只是对于该语言的一种标准而已。 - Ruan Mendes
不要忘记 JavaScript 是无类型的,一切皆为对象。请参见下面 Saul 的答案。 - Stephan Kristyn
4
确切地说,JavaScript具有类型,但以动态和弱类型的方式。例如,虽然其变量确实没有类型,但它们的值是有类型的。这是动态部分。弱表示不严格定义不同值类型之间的操作,并依赖于后台转换;例如,“Test”+{};是一个完全有效的JavaScript语句。 - Saul
18个回答

1273
JavaScript中的对象可以被视为关联数组,将键(属性)映射到值。
要从JavaScript对象中删除属性,您可以使用delete操作符:
const o = { lastName: 'foo' }
o.hasOwnProperty('lastName') // true
delete o['lastName']
o.hasOwnProperty('lastName') // false

请注意,当将delete应用于Array的索引属性时,您将创建一个稀疏数组(即,带有缺失索引的数组)。
在使用Array实例时,如果您不想创建稀疏数组 - 通常情况下是这样的 - 那么您应该使用Array#spliceArray#pop
请注意,JavaScript中的delete运算符不会直接释放内存。其目的是从对象中删除属性。当然,如果要删除的属性持有对对象o的唯一剩余引用,则o随后将以正常方式进行垃圾回收。
使用delete运算符可能会影响JavaScript引擎优化 代码的能力。

20
如果在Array对象实例上使用它来删除现有元素,例如 delete myArray[0],将会引起问题。请参考 https://dev59.com/snRC5IYBdhLWcg3wS_AF#9973592 和 Deleting array elements - Saul
5
会引起什么问题? - Gottox
28
Array对象的length属性保持不变。 - Saul
12
如果myArray真的被用作数组,就会有问题,但事实并非如此(myArray是一个不幸的名称),它是一个对象。因此在这种情况下,使用delete是可以的。请注意,即使它是作为new Array()创建并用作关联数组,仍然是可以的。不过,如果使用真正的数组,则需要注意你提出的警告。 - johndodo
2
@johndodo - 确实。这就是为什么我在我的初始评论中加上了“如果用于Array对象实例,将会引起问题”的注释。尽管如此,我仍然更喜欢一种在所有情况下都能正确执行的方法,请看下面的答案。 - Saul
显示剩余9条评论

96

JavaScript中的所有对象都是实现为哈希表/关联数组。因此,以下是等效的:

alert(myObj["SomeProperty"]);
alert(myObj.SomeProperty);

如前所述,你可以通过delete关键字从一个对象中“删除”一个属性。这个关键字有两种使用方式:

delete myObj["SomeProperty"];
delete myObj.SomeProperty;

希望额外的信息对您有所帮助...


12
需要注意的是,如果属性不是一个简单术语,则点表示法无法起作用。即 myObj['some;property'] 可以工作,但 myObj.some;property 不行(显然的原因)。另外,可能不太明显的是,在括号表示法中可以使用变量,例如 var x = 'SomeProperty'; alert(myObj[x]) - Kip
2
所有JavaScript中的对象都是以哈希表/关联数组的形式实现的 - 这是错误的。V8更喜欢将对象存储为隐藏类+密集包装字段。只有当您对它们进行奇怪的操作(例如删除字段)时,它才会放弃并在幕后使用哈希映射。 - John Dvorak
6
@JanDvorak- 嘿,你知道这个答案最初是什么时候写的吗?那个描述过去和现在对于大多数目的来说都足够了。话虽如此,我理解你一直在追求严谨。 :) - Jason Bunting

43

之前的回答都没有涉及到JavaScript本身并没有关联数组的事实 - 事实上不存在array类型,详见typeof

JavaScript拥有的是带有动态属性的对象实例。当属性与数组对象实例的元素混淆时,会发生糟糕的事情:

问题

var elements = new Array()

elements.push(document.getElementsByTagName("head")[0])
elements.push(document.getElementsByTagName("title")[0])
elements["prop"] = document.getElementsByTagName("body")[0]

console.log("number of elements: ", elements.length)   // Returns 2
delete elements[1]
console.log("number of elements: ", elements.length)   // Returns 2 (?!)

for (var i = 0; i < elements.length; i++)
{
   // Uh-oh... throws a TypeError when i == 1
   elements[i].onmouseover = function () { window.alert("Over It.")}
   console.log("success at index: ", i)
}

解决方法

要使用一种不会导致错误的通用删除函数,可以使用以下代码:

Object.prototype.removeItem = function (key) {
   if (!this.hasOwnProperty(key))
      return
   if (isNaN(parseInt(key)) || !(this instanceof Array))
      delete this[key]
   else
      this.splice(key, 1)
};

//
// Code sample.
//
var elements = new Array()

elements.push(document.getElementsByTagName("head")[0])
elements.push(document.getElementsByTagName("title")[0])
elements["prop"] = document.getElementsByTagName("body")[0]

console.log(elements.length)                        // Returns 2
elements.removeItem("prop")
elements.removeItem(0)
console.log(elements.hasOwnProperty("prop"))        // Returns false as it should
console.log(elements.length)                        // returns 1 as it should

9
这个解决方案有两个问题:它隐藏了JS中数组和对象完全不同的事实(你知道,但OP显然不知道),而且它使用了原型。如果OP学习数组和对象(并相应地命名变量),那他会更好——试图隐藏这两者之间的区别只会让他陷入更多麻烦。当然,这只是我的意见。 - johndodo
2
@johndodo - 在JS中,所有的Array都是对象,尝试使用typeof new Array();typeof []进行验证。 Array只是一种特定类型的对象,而不是完全“不同的东西”。在JS中,对象通过它们的构造函数名称和原型链来区分,参见基于原型的编程 - Saul
11
你没有理解重点。我知道数组也是对象,但这并不意味着把它们用作这样的对象是明智的。程序员应该决定是否要将其用作数组(使用 push、pop、[] 等)或对象/“关联数组”。混合使用不是一个好的方法,正是因为你的解决方案试图隐藏的问题。如果你事先决定要使用哪种设计模式(数组或对象),就不会出现这样的问题。 - johndodo
9
@johndodo - 你具体指的是哪些问题?上述代码的目的是通过提供一个简单的多态函数来解决delete操作符在处理Array方面存在的不足。 - Saul
1
delete 没有缺陷。 delete 的设计目的是删除属性。就这样。将 delete 运算符应用于数组的索引会删除该索引。还需要什么呢?你会得到一个稀疏数组,这是语言的一个特性。如果您不想要稀疏数组,请勿删除索引:使用 splicepop - Ben Aston
显示剩余2条评论

40

这只是删除了数组中的对象,但数组长度仍然保持不变。

要从数组中移除元素,你需要做像这样的操作:

array.splice(index, 1);

12
确实如此,但在这种情况下并没有使用数组,只是一个普通的对象,因此它没有长度或剪切方法。 - MooGoo
2
除非我们不谈论数组,否则这个说法是100%错误的。 - Drenai

22

虽然已被接受的答案是正确的,但它缺少了解释为什么它有效的说明。

首先,你的代码应该反映出这不是一个数组:

var myObject = new Object();
myObject["firstname"] = "Bob";
myObject["lastname"] = "Smith";
myObject["age"] = 25;

请注意,所有对象(包括Array)都可以以这种方式使用。但是,请不要指望标准的JavaScript数组函数(如pop、push等)能够用于对象!

正如接受的答案中所说,您可以使用delete从对象中删除条目:

delete myObject["lastname"]

你应该决定使用哪种方式 - 要么是对象(关联数组/字典),要么是数组(映射表)。切勿混用两者。


8
非常好的回答。我只想建议任何阅读这篇文章的人,JavaScript中的数组不应该抽象为“映射”,而应该是“列表”。因为当使用数组时,您不应该尝试控制元素的索引。如果您尝试那样做...嗯,就别尝试了:D - rodolfo42

12

9

正如其他答案所指出的那样,你没有使用JavaScript数组,而是使用了JavaScript对象,它几乎像其他语言中的关联数组一样工作,只是所有键都转换为字符串。新的Map会将键存储为它们的原始类型。

如果你有一个数组而不是一个对象,你可以使用数组的.filter函数来返回一个新数组,其中不包含要删除的项:

var myArray = ['Bob', 'Smith', 25];
myArray = myArray.filter(function(item) {
    return item !== 'Smith';
});

如果您使用的是旧版本浏览器和 jQuery,jQuery 有一个 $.grep 方法,其功能类似:

myArray = $.grep(myArray, function(item) {
    return item !== 'Smith';
});

1
完美的解释。我使用 filter 来达到期望的结果。您能否解释一下返回值是如何将对象从数组中删除的?我猜想只要数组不包含您提供的字符串,它就会返回该数组。 - Edward

6
如果您想要更加实用和优美的方法,可以采取以下措施:
const o = { firstName: "foo", lastName: "bar" };
const { lastName, ...removed } = o;
lastName // bar
removed // { firstName: "foo" }

请注意,如果对象中没有剩余的项,则removed的值将为未定义。

6
使用 "delete" 关键字,可以从 JavaScript 数组中删除数组元素。
例如,
考虑以下语句。
var arrayElementToDelete = new Object();

arrayElementToDelete["id"]           = "XERTYB00G1";
arrayElementToDelete["first_name"]   = "Employee_one";
arrayElementToDelete["status"]       = "Active";

delete arrayElementToDelete["status"];

代码的最后一行将从数组中删除键为“status”的数组元素。

6
使用方法splice从对象数组中完全删除一项:
Object.prototype.removeItem = function (key, value) {
    if (value == undefined)
        return;

    for (var i in this) {
        if (this[i][key] == value) {
            this.splice(i, 1);
        }
    }
};

var collection = [
    { id: "5f299a5d-7793-47be-a827-bca227dbef95", title: "one" },
    { id: "87353080-8f49-46b9-9281-162a41ddb8df", title: "two" },
    { id: "a1af832c-9028-4690-9793-d623ecc75a95", title: "three" }
];

collection.removeItem("id", "87353080-8f49-46b9-9281-162a41ddb8df");

1
这是一个更通用的解决方案,可以添加到您的JS文件中,该方法将对所有数组而非仅限于某个特定数组可用。 - Hussain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接