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

ttb*_*ack 7 javascript browser requirejs

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

var data = [];
data ["first"] = [];
data ["first"]["second"] = [];
data ["first"]["second2"] = "hello";
Run Code Online (Sandbox Code Playgroud)

它大约是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));
Run Code Online (Sandbox Code Playgroud)

结果是

[]:34 {}:34

sizeOf实际上是相同的.但是,[]可能会触发内存不足问题.我不确定是解析它的requirejs是触发它还是某些V8优化路径.我认为Lint工具甚至不建议反对这种做法所以它在实践中以"正确"的方式是相当模糊的

Jor*_*ing 5

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

var data = [];
data["first"] = [];
data["first"]["second"] = [];
Run Code Online (Sandbox Code Playgroud)

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

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

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

PS作为一种风格问题,在处理对象时,请考虑使用属性表示法(或"点符号",即ie foo.bar)代替下标符号(即foo["bar"]):

var data = {};
data.first = {};
data.first.second = {};
data.first.second2 = "hello";
Run Code Online (Sandbox Code Playgroud)

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

var data = {
  first: {
    second: {},
    second2: "hello"
  }
};
Run Code Online (Sandbox Code Playgroud)

这也完全相同,可以帮助您查看对象的"结构"(只要您对缩进有规律).

大多数JavaScript样式指南都说您应该始终使用"点表示法",除非您有可能导致语法错误的键.例如,如果您有一个名为的属性"foo/bar",您显然不能这样做:

var obj.foo/bar = 1;
Run Code Online (Sandbox Code Playgroud)

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

var obj["foo/bar"] = 1;
Run Code Online (Sandbox Code Playgroud)

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