我有一个可能包含数千个对象的模型。我想知道有什么最有效的方法来存储这些对象,并在获得对象的 id 后检索单个对象。id 是长数字。
在选项 1 中,它是一个索引递增的简单数组。在选项 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];
}
更新:
好吧,我明白在第二个选项中使用数组是不可能的。所以第二个选项的声明行应该是var a = {};`,唯一的问题是:在检索具有给定 id 的对象时,哪种方式性能更好:数组还是以 id 为键的对象。
另外,如果我必须对列表进行多次排序,答案会改变吗?
**简而言之:大多数情况下,数组比对象更快。但没有百分之百正确的解决方案。
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'});
}
您的问题存在一些误解。
这些是数组:
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 内存][4]
这其实根本不是性能问题,因为数组和对象的工作方式截然不同(至少应该是这样)。数组有一个连续的索引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
我试着把它带到下一个维度,从字面上理解。
给定一个 2 维数组,其中 x 轴和 y 轴的长度总是相同的,这样做是否更快?
a) 通过创建一个二维数组来查找单元格,先查找第一个索引,然后再查找第二个索引,即
var arr=[][]
var cell=[x][y]
或
b) 创建一个用字符串表示 x 和 y 坐标的对象,然后对该对象进行一次查找,即
var obj={}
var cell = obj['x,y']
结果: 结果发现,对数组进行两次数字索引查找要比对对象进行一次属性查找快得多。
结果在此: