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

对于Javascript中的嵌套对象,{}消耗的内存是否比[]少?,javascript,browser,requirejs,Javascript,Browser,Requirejs,我有一些遗留的JS代码,可以用[]创建一个巨大的嵌套对象结构。 代码是这样的 var data = []; data ["first"] = []; data ["first"]["second"] = []; data ["first"]["second2"] = "hello"; 它大约有250+KB的javascript,相当大。当我试图用requirejs将它包装起来以加载到另一个requirejs模块时,它抛出内存不足错误 如果我在使用[]的地方使用{},错误就会消失 我在周末做了一

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

var data = [];
data ["first"] = [];
data ["first"]["second"] = [];
data ["first"]["second2"] = "hello";
它大约有250+KB的javascript,相当大。当我试图用requirejs将它包装起来以加载到另一个requirejs模块时,它抛出内存不足错误

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

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

我没有足够的关于JS内存检测的知识,也没有在浏览器引擎中使用{}或[]进行比较,所以很难得出结论。欢迎就如何使用{}vs.[]提供任何提示或建议

更新:我昨天通过node尝试了一些sizeOf()。我使用了所有现有的工具:“js sizeof”、“object sizeof”、“sizeof”

代码:

结果是

[]:34 {}:34


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

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

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

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

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

作为样式的问题,考虑使用属性记号(或“点符号”,即<代码> fo.bar <代码>),而不是下标表示法(即<代码> Fo[[ 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;

…这是完全正确的。这些情况往往是例外,因此我鼓励您始终使用点表示法,除非您必须使用下标表示法。

它们都是对象,但如果有什么不同的话,
{}
将消耗更多,因为您必须存储键的字符串,而不仅仅是整数索引。@MarcB:错误。这将取决于您使用的键,而不是它是否是数组。。我的理解是ary=[1,2,3]初始化一个对象{1:1,2:2,3:3},这就是为什么ary[10000000]=123可以在不破坏机器的情况下工作的原因。所有数组都是对象,所有对象都像关联数组(列表(LISP))一样工作,但它们有一些额外的方法,可以让您合理地初始化它们,获取长度等。上面的示例最好用JSON编写,但我目前不同意您的理由。你能说服我吗?是的,这正是我在第一段中写的。我没有说服你的动机,所以我担心你会对我的回答感到不满意。我不是故意粗鲁,我只是认为我错了。啊,好吧,我为我的粗鲁道歉。我想知道记忆的缺失是否与Requirejs的工作原理有关。我还在业力测试中使用它,这增加了另一层抽象。虽然我同意我们可能不应该使用数组作为对象。我只是需要确定一下,在我们改变500多个这样的脚本之前
var obj.foo/bar = 1;
var obj["foo/bar"] = 1;