对于 Javascript 中的嵌套对象,{} 消耗的内存是否少于 []?

Does {} consume less memory than [] for nested objects in Javascript?

我有一些遗留的 JS 代码用 [] 创建了一个巨大的嵌套对象结构。 代码是这样的

var data = [];
data ["first"] = [];
data ["first"]["second"] = [];
data ["first"]["second2"] = "hello";

大约是 javascript 的 250+ KB,相当大。当我尝试用 requirejs 包装它以加载到另一个 requirejs 模块时,它抛出内存不足错误。

如果我在使用 [] 的地方使用 {},错误就会消失。

我在周末做了一些关于 [] 与 {} 的作业,原因似乎是使用关联数组作为嵌套字典在 Javascript 中可能存在漏洞,因为数组扩展了一个 JS 对象并且可能有将新对象附加到其中时会进行更多更新。但它能解释内存消耗问题吗?或者与Requirejs如何解析模块的对象有关?

我对 JS 内存检测的了解不够,在浏览器引擎中使用 {} 或 [] 进行比较,因此很难得出结论。欢迎任何关于如何检测 {} 与 [] 的提示或建议。

更新: 我昨天通过节点尝试了一些 sizeOf() 。我使用了所有现有的:"js-sizeof"、"object-sizeof"、"sizeof"

代码:

var sizeof = require('object-sizeof');


var obj = [];
obj['ball'] = 'hello';
obj['air'] = 'hello';
obj['ball']['fire'] = 'world';
obj['ball']['ice'] = [];
console.log(sizeof(obj));

var obj2 = {};
obj2['ball'] = 'hello';
obj2['air'] = 'hello';
obj2['ball']['fire'] = 'world';
obj2['ball']['ice'] = [];
console.log(sizeof(obj2));

结果是

[]: 34 {}: 34

sizeOf 实际上是相同的。,但也许 [] 发生了其他事情,可能会触发内存不足问题。我不确定是 requirejs 解析它触发了它还是某些 V8 优化路径。我认为 Lint 工具甚至不建议反对这种做法,因此在实践中 "right" 方式是哪种方式相当含糊

JavaScript 中没有 "associated array" 这样的东西。 [ 1, 2, 3 ] 是数组字面量语法;它初始化一个数组。 { foo: "bar" } 是对象字面量语法;它初始化一个对象。然而,JavaScript 的一个怪癖是数组也恰好是对象,这就是为什么这段代码 "works":

var data = [];
data["first"] = [];
data["first"]["second"] = [];

...但你不应该这样做,因为它没有任何意义。您正在初始化一个空数组 ([]),但是您并没有像使用数组一样使用它——而是像使用对象一样使用它。如果您使用 属性 名称(data["first"],相当于 data.first)而不是整数键(data[0]),那么您需要使用对象。当您要像使用对象一样使用数组时,没有任何情况应该初始化它。

根据经验,如果您需要每个项目都有一个名称,或者需要能够通过名称快速访问它们,请使用对象 ({}) 并使用字符串作为键。如果您需要能够按顺序迭代项目,请使用带有整数的数组作为键。

我不知道你的内存不足错误的确切原因——尤其是在没有看到你的实际代码的情况下——但你肯定应该使用对象 ({}) ,而不是数组 ([]) 当您不使用整数键时。 JavaScript 引擎会尽其所能进行优化,数组和对象也不例外,因此当您以引擎不期望的方式使用数组时,可能会导致性能或内存问题,这并不奇怪。

P.S。作为风格问题,在处理对象时考虑使用 属性 符号(或 "dot notation," 即 foo.bar)而不是下标符号(即 foo["bar"]):

var data = {};
data.first = {};
data.first.second = {};
data.first.second2 = "hello";

这与您发布的代码完全相同,但它更易于阅读,并且可能有助于您记住对象和数组有不同的用途。您也可以将其表示为单个对象文字:

var data = {
  first: {
    second: {},
    second2: "hello"
  }
};

这也完全相同,可以帮助您查看对象的 "structure"(只要您遵守缩进规范)。

大多数 JavaScript 风格指南都说你应该总是使用 "dot notation" 除非你有会导致语法错误的键。例如,如果你有一个名为"foo/bar"的属性,你显然不能这样做:

var obj.foo/bar = 1;

...因为这是语法错误。所以你必须这样做:

var obj["foo/bar"] = 1;

...完全正确。这些情况往往是例外,所以我鼓励始终使用点符号,除非您必须使用下标符号。