JavaScript 中的数组与对象效率更新 2017 - 测试和结果原始帖子 - 说明

2022-08-30 02:05:08

我有一个可能包含数千个对象的模型。我想知道一旦我有id,存储它们并检索单个对象的最有效方法是什么。ID 是长数字。

所以这些是我正在考虑的2个选项。在选项一中,它是一个具有递增索引的简单数组。在选项2中,它是一个关联数组,也许是一个对象,如果它有所作为的话。我的问题是哪一个更有效,当我主要需要检索单个对象时,但有时也会循环浏览它们并进行排序。

具有非关联数组的选项一:

var a = [{id: 29938, name: 'name1'},
         {id: 32994, name: 'name1'}];
function getObject(id) {
    for (var i=0; i < a.length; i++) {
        if (a[i].id == id) 
            return a[i];
    }
}

带有关联数组的选项二:

var a = [];  // maybe {} makes a difference?
a[29938] = {id: 29938, name: 'name1'};
a[32994] = {id: 32994, name: 'name1'};
function getObject(id) {
    return a[id];
}

更新:

好吧,我明白在第二个选项中使用数组是不可能的。因此,声明行的第二个选项应该是:唯一的问题是:在检索具有给定id的对象时,什么表现更好:数组或id是键的对象。var a = {};

而且,如果我必须多次对列表进行排序,答案会改变吗?


答案 1

简短版本:数组大多比对象快。但是没有100%正确的解决方案。

更新 2017 - 测试和结果

var a1 = [{id: 29938, name: 'name1'}, {id: 32994, name: 'name1'}];

var a2 = [];
a2[29938] = {id: 29938, name: 'name1'};
a2[32994] = {id: 32994, name: 'name1'};

var o = {};
o['29938'] = {id: 29938, name: 'name1'};
o['32994'] = {id: 32994, name: 'name1'};

for (var f = 0; f < 2000; f++) {
    var newNo = Math.floor(Math.random()*60000+10000);
    if (!o[newNo.toString()]) o[newNo.toString()] = {id: newNo, name: 'test'};
    if (!a2[newNo]) a2[newNo] = {id: newNo, name: 'test' };
    a1.push({id: newNo, name: 'test'});
}

test setup test results

原始帖子 - 说明

你的问题中有一些误解。

Javascript 中没有关联数组。仅数组和对象。

这些是数组:

var a1 = [1, 2, 3];
var a2 = ["a", "b", "c"];
var a3 = [];
a3[0] = "a";
a3[1] = "b";
a3[2] = "c";

这也是一个数组:

var a3 = [];
a3[29938] = "a";
a3[32994] = "b";

它基本上是一个有孔的数组,因为每个数组都有连续的索引。它比没有孔的数组慢。但是,手动迭代数组甚至更慢(大多数情况下)。

这是一个对象:

var a3 = {};
a3[29938] = "a";
a3[32994] = "b";

以下是三种可能性的性能测试:

查找数组与孔隙数组与对象性能测试

在Smashing Magazine上关于这些主题的精彩阅读:编写快速内存高效的JavaScript


答案 2

这根本不是一个真正的性能问题,因为数组和对象的工作方式非常不同(或者至少应该如此)。数组有一个连续的索引,而对象将任意键映射到任意值。如果要提供特定键,唯一的选择是对象。如果你不关心键,那就是一个数组。0..n

如果您尝试在数组上设置任意(数字)键,则确实会降低性能,因为从行为上讲,数组将填充介于两者之间的所有索引:

> foo = [];
  []
> foo[100] = 'a';
  "a"
> foo
  [undefined, undefined, undefined, ..., "a"]

(请注意,数组实际上不包含 99 个未定义的值,但它将以这种方式运行,因为您 [应该] 在某个时候迭代数组。

这两个选项的文本应该非常清楚地说明如何使用它们:

var arr = ['foo', 'bar', 'baz'];     // no keys, not even the option for it
var obj = { foo : 'bar', baz : 42 }; // associative by its very nature