JavaScript数组随机索引的插入和删除

yoj*_*o87 3 javascript arrays

我正在使用随机创建的索引将一些项插入到数组中,例如:

var myArray = new Array();
myArray[123] = "foo";
myArray[456] = "bar";
myArray[789] = "baz";
...
Run Code Online (Sandbox Code Playgroud)

换句话说,数组索引不以零开头,它们之间会有"数字间隙".我的问题是:

  • 这些数字间隙是否会以某种方式分配(因此需要一些内存),即使它们没有分配值?
  • 当我从上面的例子中删除myArray [456]时,这个项目下面的项目会被重新定位吗?

编辑:关于插入/删除后重新定位项目的问题/关注 - 我想知道内存发生了什么,而不是索引.来自维基百科文章的更多信息:

链接列表与动态数组相比有几个优点.在列表的特定点处插入元素是恒定时间操作,而在随机位置插入动态数组将需要平均移动一半元素,并且在最坏情况下移动所有元素.虽然可以通过某种方式将其插槽标记为"空闲"而在恒定时间内从数组中"删除"元素,但这会导致碎片阻碍迭代的执行.

T.J*_*der 6

这些数字间隙是否会以某种方式分配(因此需要一些内存),即使它们没有分配值?

不,JavaScript数组根本不是真正的数组(见下文),未使用的索引不占用内存.

当我从上面的例子中删除myArray [456]时,这个项目下面的项目会被重新定位吗?

如果你在谈论数组索引,它取决于你如何删除它:如果你使用delete关键字,没有.如果您使用该splice功能或类似功能,是的.就内存而言,不,其他条目不会重新定位(无论如何),并且由不再存在的条目引用的任何内存(无论是因为a delete还是a splice或a pop或类似)都可以被垃圾回收器回收.链接列表在JavaScript中几乎没有优于数组或普通旧对象的优势,您很少看到它们.添加到JavaScript数组(或对象)可能是一个接近恒定时间的操作(实现可能需要进行散列,可能需要进行一些B树结构或类似的遍历,但这完全是特定于实现的),因为删除.

正如您所描述的那样,正如Zevon指出的那样,您可能根本不需要阵列.如果你需要一个length属性或一个依赖它的数组函数,你真的只需要一个数组.否则,你最好用一个普通的旧物体:

var obj = {};
obj[123] = "foo";
obj[456] = "bar";
obj[789] = "baz";
Run Code Online (Sandbox Code Playgroud)

这是完全有效的JavaScript.您在括号(123等)中使用的值被强制转换为字符串(无论您是处理数组还是普通对象),因此密钥实际上是"123"等等(无论您是使用a Array或a Object).您甚至可以使用for..in控制结构遍历它们(详情请参见此处).


我的意思是"......根本不是阵列"?从字面上看.JavaScript对象是键 - >值映射,JavaScript数组只不过是具有键和值的对象,以及对作为数字字符串的键的特殊处理,以及特殊length属性.虽然我们通常将数组"索引"作为数字写入,就像它们是字符串的所有属性名称一样 - a[0]被转换为a["0"](尽管实现可以自由地优化它,只要行为保持符合规范).本规范的第15.4节对此进行了介绍,该段以本段开头:

数组对象对特定类的属性名称进行特殊处理.当且仅当ToString(ToUint32(P))等于P且ToUint32(P)不等于2 ^ 32-1时,属性名P(以String值的形式)是数组索引.属性名称为数组索引的属性也称为元素.每个Array对象都有一个属性,其值始终是小于2 ^ 32的非负整数.该属性的值在数值上大于名称为数组索引的每个属性的名称; 无论何时创建或更改Array对象的属性,都会根据需要调整其他属性以保持此不变量.具体来说,每当添加名称为数组索引的属性时,如果需要,该属性将更改为该数组索引的数值之一; 每当属性发生更改时,将自动删除名称为数组索引且值不小于新长度的每个属性.此约束仅适用于Array对象的自身属性,并且不受可能从其原型继承的长度或数组索引属性的影响.lengthlengthlengthlength