JavaScript中的数组与对象的效率

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

所以这是我正在考虑的两个选项。 在选项一中,它是一个带有递增索引的简单数组。 在选项2中,它是一个关联数组,也许是一个对象,如果它有所作为。 我的问题是哪一个更有效率,当我主要需要检索一个单一的对象,但也有时循环和sorting。

// option one: non associative array 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]; } } // option two: associative array 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是关键。

而且,如果我必须多次sorting清单,答案才会改变吗?

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

更新2017年 – testing和结果

 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'}); } 

测试设置 检测结果

原来的后解释

你的问题有一些误解。

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"; 

它基本上是一个有洞的数组,因为每个数组都有连续的索引。 它比没有孔的arrays慢。 但是通过数组手动迭代更慢(大部分)。

这是一个对象:

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

这是一个三种可能性的性能testing:

查找数组与vsy数组vs对象性能testing

在“Smashing”杂志上对这些主题的精彩阅读: 编写快速高效的JavaScript

这根本不是性能问题,因为数组和对象的工作方式非常不同(至less应该是这样)。 数组有一个连续索引0..n ,而对象将任意键映射到任意值。 如果想提供特定的键,唯一的select是一个对象。 如果你不关心按键,它是一个数组。

如果你尝试在一个数组上设置任意的(数字)键,你确实会有性能损失 ,因为这个数组在行为上会填充所有的索引:

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

(请注意,数组实际上并不包含99个undefined值,但是它会以这种方式运行,因为您应该在某个时间点迭代数组。

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

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

使用ES6的最高性能方式是使用Map。

 var myMap = new Map(); myMap.set(1, 'myVal'); myMap.set(2, { catName: 'Meow', age: 3 }); myMap.get(1); myMap.get(2); 

您可以使用shim( https://github.com/es-shims/es6-shim )来使用ES6function。

性能会因浏览器和场景而异。 但是这里有一个例子, Map是最高性能的: https : //jsperf.com/es6-map-vs-object-properties/2


参考https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map

我试图从字面上理解这一点。

给定一个二维数组,其中x和y轴始终是相同的长度,是否更快:

a)通过创build一个二维数组并查找第一个索引,然后查找第二个索引,即:

 var arr=[][] var cell=[x][y] 

要么

b)用x和y坐标的string表示创build一个对象,然后对该obj进行一次查找,即:

 var obj={} var cell = obj['x,y'] 

结果:
事实certificate,在数组上执行两个数字索引查找比在对象上查找一个属性要快得多。

结果在这里:

http://jsperf.com/arr-vs-obj-lookup-2

这取决于使用情况。 如果查找对象的情况非常快。

这是一个Plunker示例来testing数组和对象查找的性能。

https://plnkr.co/edit/n2expPWVmsdR3zmXvX4C?p=preview

你会看到的; 在5.000长度的数组集合中查找5.000个项目,接收3000 milisecons

然而,在对象中查找5.000项目有5.000属性,只需要23 milisecons

也使得对象树没有太大的区别

NodeJS中,如果您知道该ID ,则与object[ID]相比,循环遍历数组的速度非常慢。

 const uniqueString = require('unique-string'); const obj = {}; const arr = []; var seeking; //create data for(var i=0;i<1000000;i++){ var getUnique = `${uniqueString()}`; if(i===888555) seeking = getUnique; arr.push(getUnique); obj[getUnique] = true; } //retrieve item from array console.time('arrTimer'); for(var x=0;x<arr.length;x++){ if(arr[x]===seeking){ console.log('Array result:'); console.timeEnd('arrTimer'); break; } } //retrieve item from object console.time('objTimer'); var hasKey = !!obj[seeking]; console.log('Object result:'); console.timeEnd('objTimer'); 

结果是:

 Array result: arrTimer: 12.857ms Object result: objTimer: 0.051ms 

即使查找ID是数组/对象中的第一个:

 Array result: arrTimer: 2.975ms Object result: objTimer: 0.068ms