Javascript 数组稀疏吗?

IT技术 javascript sparse-matrix
2021-01-28 02:51:32

也就是说,如果我使用当前时间作为数组的索引:

array[Date.getTime()] = value;

解释器会实例化从 0 到现在的所有元素吗?不同的浏览器有不同的做法吗?

我记得曾经在AIX内核中有一个错误,它会根据请求创建伪 tty,但是如果你这样做了,比如“echo > /dev/pty10000000000”,它会创建 /dev/pty0、/dev/pty1, ....然后摔倒死了。在贸易展上很有趣,但我不希望这发生在我的客户身上。

6个回答

对,他们是。它们实际上是内部的哈希表,因此您不仅可以使用大整数,还可以使用字符串、浮点数或其他对象。toString()在添加到哈希之前,所有键都通过转换为字符串您可以使用一些测试代码来确认这一点:

<script>
  var array = [];
  array[0] = "zero";
  array[new Date().getTime()] = "now";
  array[3.14] = "pi";

  for (var i in array) {
      alert("array["+i+"] = " + array[i] + ", typeof("+i+") == " + typeof(i));
  }
</script>

显示:

array[0] = zero, typeof(0) == string
array[1254503972355] = now, typeof(1254503972355) == string
array[3.14] = pi, typeof(3.14) == string

请注意我如何使用for...in语法,它只为您提供实际定义的索引。如果您使用更常见for (var i = 0; i < array.length; ++i)的迭代方式,那么您显然会遇到非标准数组索引的问题。

@John:length仅在for..in循环中不可见,因为它DontEnum设置标志;在 ES5 中,property 属性被调用enumerable并且可以通过显式设置Object.defineProperty()
2021-03-19 02:51:32
那么你应该只使用字符串作为对象键,不多也不少。String 应该是你要使用的类型,key 的类型应该是 String。你不应该使用整数,也不使用非整数,除非你继续转换为字符串。任意对象是正确的。
2021-03-19 02:51:32
JavaScript 中的所有对象键总是String; toString()在下标中放置的任何其他内容都会被-ed。将此与 large Number 的整数不精确性结合起来,这意味着如果您设置a[9999999999999999]=1,a[10000000000000000]将是 1(以及更多令人惊讶的行为)。使用非整数作为键是非常不明智的,任意对象都是正确的。
2021-04-01 02:51:32
如果可能,大多数 JS 实现将数字索引属性存储在实际数组中;不过,这是幕后的魔法:从语言的角度来看,数组是具有魔法length属性的常规对象
2021-04-02 02:51:32
数组索引必须是整数。array[3.14] = pi 有效,因为 Array 从 Object 继承。示例:var x=[];x[.1] = 5; 然后 x 的长度仍然为 0。
2021-04-10 02:51:32

JavaScript 数组的具体实现方式因浏览器而异,但它们通常会回退到稀疏实现 - 很可能与用于常规对象的属性访问相同的实现 - 如果使用实际数组效率低下。

您必须询问对特定实现有更多了解的人来回答是什么触发了从密集到稀疏的转变,但您的示例应该是完全安全的。如果你想得到一个密集数组,你应该用一个显式的长度参数调用构造函数,并希望你能真正得到一个。

有关olliej 的更详细描述,请参阅此答案

如果你说类似foo = new Array(10000). 然而,这应该工作:foo = Array.apply(null, {length: 10});
2021-03-13 02:51:32

您可以通过使用专为此类事情设计的 javascript 语法来避免该问题。你可以把它当作一本字典,但是“for ... in ...”语法会让你把它们全部抓起来。

var sparse = {}; // not []
sparse["whatever"] = "something";

Javascript 对象是稀疏的,数组只是具有自动维护的长度属性(实际上比最大索引大 1,而不是定义元素的数量)和一些附加方法的专用对象无论哪种方式,您都是安全的;如果您需要它的额外功能,请使用数组,否则使用对象。

那是从语言的角度来看;实现实际上使用真实数组来存储密集的数字属性
2021-03-22 02:51:32

与 JavaScript 一样,答案通常是“它有点奇怪……”

内存使用没有定义,任何实现都是愚蠢的。理论上,const a = []; a[1000000]=0;可以像const a = [];. 在实践中,即使是微软也避免了这些实现。

Justin Love指出,length 属性是最高索引集。但只有在索引是整数时才更新。

所以,数组是稀疏的。但是像reduce()、Math.max()和“for ... of”这样的内置函数将遍历从0到长度的整个可能整数索引范围,访问许多返回'undefined'的函数。但是 'for ... in' 循环可能会如您所愿,只访问定义的键。

下面是一个使用 Node.js 的例子:

"use strict";
const print = console.log;

let a = [0, 10];
// a[2] and a[3] skipped
a[4] = 40;
a[5] = undefined;  // which counts towards setting the length
a[31.4] = 'ten pi';  // doesn't count towards setting the length
a['pi'] = 3.14;
print(`a.length= :${a.length}:, a = :${a}:`);
print(`Math.max(...a) = :${Math.max(a)}: because of 'undefined values'`);
for (let v of a) print(`v of a; v=:${v}:`);
for (let i in a) print(`i in a; i=:${i}: a[i]=${a[i]}`);

给予:

a.length= :6:, a = :0,10,,,40,:
Math.max(...a) = :NaN: because of 'undefined values'
v of a; v=:0:
v of a; v=:10:
v of a; v=:undefined:
v of a; v=:undefined:
v of a; v=:40:
v of a; v=:undefined:
i in a; i=:0: a[i]=0
i in a; i=:1: a[i]=10
i in a; i=:4: a[i]=40
i in a; i=:5: a[i]=undefined
i in a; i=:31.4: a[i]=ten pi
i in a; i=:pi: a[i]=3.14

但。还有更多关于 Arrays 的极端情况尚未提及。