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

时间:2015-06-02 15:31:10

标签: javascript browser requirejs

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

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

大约250多KB的javascript,相当大。当我尝试用requirejs将其包装到另一个requirejs模块中时,它会抛出Out Of Memory错误。

如果我使用{},那么错误就会消失。

我周末在[]和{}上做了一些功课,原因似乎是使用关联数组作为嵌套词典可能在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工具甚至建议反对这种做法所以它是相当模糊的,这是'#34;对"实践中的方式

1 个答案:

答案 0 :(得分:5)

JavaScript中没有“关联数组”这样的东西。 [ 1, 2, 3 ]是数组文字语法;它初始化一个数组。 { foo: "bar" }是对象文字语法;它初始化一个Object。然而,JavaScript的一个怪癖是Arrays也恰好是Objects,这就是为什么这段代码“有用”的原因:

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

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

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

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

P.S。作为一种风格问题,在处理对象时,请考虑使用属性表示法(或“点符号”,即foo.bar)而不是下标符号(即foo["bar"]):

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

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

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

这也完全等效,可以帮助您查看对象的“结构”(只要您对缩进有规律)。

大多数JavaScript样式指南都说您应该始终使用“点表示法”,除非您的密钥会导致语法错误。例如,如果您有一个名为"foo/bar"的属性,则显然无法执行此操作:

var obj.foo/bar = 1;

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

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

......这是完全有效的。这些情况往往是例外,所以我鼓励总是使用点表示法,除非你必须使用下标符号。