为什么在Javascript中删除一个项时,数组不会重新调整大小?

6
在许多编程语言中,标准的动态列表(非固定大小数组)类型在删除一个项目后会进行调整大小:
Python:
myList = ['a', 'b', 'c']
del(myList[0])
print(len(myList)) # Prints '2'

C#:

var myList = new List<string> {"a", "b", "c"};
myList.RemoveAt(0);
Console.WriteLine(myList.Count); // Prints '2'

等等。

然而,在Javascript中,即使元素求值为undefined这里告诉我它与array[index] = undefined不同),列表长度仍保持不变:

Javascript:

var myArray = ['a', 'b', 'c']
delete myArray[0]
console.log(myArray.length) // Prints '3'
console.log(myArray) // Prints "[ , 'b', 'c' ]" in node, '[undefined × 1, "b", "c"]' in Chrome

myArray[0] = undefined
console.log(myArray) // Prints "[ undefined, 'b', 'c' ]" on both node and Chrome

myArray.splice(0, 1)
console.log(myArray) // Prints "['b', 'c']"

我的问题是:

  • JS数组的delete行为是设计上的还是由于担心破坏传统代码而无法修复的疏忽?
  • 取代被删除的数组元素的“类似未定义”的值具体是什么?

(我应该意识到这是一个重复的问题。那个重复的目标会列入我的下一步计划... :-)) - T.J. Crowder
在JavaScript中,“delete”指令不是特定于数组的。它是一条指令,您可以在所有JS对象上使用以删除特定属性。这意味着“delete”不会删除数组中的项,而是删除键(数组对象的属性),并将数组转换为稀疏数组。在JS中,这是通过删除项将密集数组变成稀疏数组的唯一方法。因此它非常有价值。 - Redu
一个未定义的插槽具有未定义的值,但是 hasOwnProperty 可以显示所有内容。请记住,对象键不保证对象值,其中一个可以是 _undefined_,这与请求不存在的属性相同。 - dandavis
2个回答

4
您对 deleteRemoveAt 的比较是不正确的,它们并不执行相同的操作;要实现相同的操作,应该使用 splice

var myArray = ['a', 'b', 'c']
myArray.splice(0, 1);
console.log(myArray.length) // Prints '2'

delete会删除一个条目而不重新排序其他条目,创建一个稀疏数组(一些条目完全缺失的数组)。delete并不是真正用于数组,它是用于从对象中删除属性的;但它适用于数组,因为在JavaScript中标准(例如非类型化)数组根本就不是数组*,它们是具有特殊处理某些属性的对象,例如那些名称为“数组索引”的属性(其定义为字符串名称“...其中数值i在范围+0 ≤ i < 2^32-1内”)和length
如果你使用deletelength的值将被更改:
  • 使用任何方法添加或删除条目(splicepush等)。
  • 通过分配到等于或大于length的索引来添加条目。
  • 直接分配给length:如果您增加length,则会使数组稀疏;如果您减少它,则会删除该索引或以上的任何条目。例如,如果您有一个数组['a','b','c','d','e']并执行theArray.length = 3,它将不再具有索引3('d')或4('e')处的条目。

JS数组删除行为是按设计还是无法修复的疏忽,因为担心破坏旧代码?

按设计。如上所述,delete主要是用于从对象中删除属性。

替换已删除的数组元素的“类似未定义”的值是什么?

没有这种方法。这是标准数组作为对象的副产品之一:如果您尝试从一个对象中读取它没有的属性的值,那么“get”操作的结果就是值undefined。并不是对象中有一个类似于undefined的值,而是该对象根本没有这个名称的属性。这个例子可能会有用:

var o = {}; // A non-array object
console.log(o.noSuchProperty);    // undefined
console.log(o["noSuchProperty"]); // undefined
console.log(o[2]);                // undefined

var a = []; // An array object
console.log(a.noSuchProperty);    // undefined
console.log(a["noSuchProperty"]); // undefined
console.log(a[2]);                // undefined


* (这是我瘦弱的小博客上的一篇文章)


啊,有趣!我把数组的REPL表示和实际值混淆了,因为至少Chrome的输出暗示着与“undefined”有关的内容,而实际上它只是告诉你那里没有东西。我也不知道“length”是可设置的,所以谢谢你。 - svbnet

1

1
但是实际上这样设置为undefined并不正确。当一个属性被删除时,它就是被删除了。将其设置为undefined与此不同。 - zerkms
一个未定义的插槽具有_undefined_的值,但hasOwnProperty将显示所有内容。 - dandavis

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