JavaScript中的数组与对象效率

Mos*_*ham 126 javascript performance

我有一个可能有数千个物体的模型.我想知道什么是最有效的存储方式和一旦我拥有它的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];
    }
}
Run Code Online (Sandbox Code Playgroud)

选项二与关联数组:

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

更新:

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

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

Alp*_*Alp 137

简短版本:数组大多比对象快.但没有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'});
}
Run Code Online (Sandbox Code Playgroud)

测试设置 检测结果

原帖 - 解释

你的问题有一些误解.

Javascript中没有关联数组.只有数组和对象.

这些是数组:

var a1 = [1, 2, 3];
var a2 = ["a", "b", "c"];
var a3 = [];
a3[0] = "a";
a3[1] = "b";
a3[2] = "c";
Run Code Online (Sandbox Code Playgroud)

这也是一个数组:

var a3 = [];
a3[29938] = "a";
a3[32994] = "b";
Run Code Online (Sandbox Code Playgroud)

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

这是一个对象:

var a3 = {};
a3[29938] = "a";
a3[32994] = "b";
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 这实际上取决于您使用的数据的数据和大小.使用数组时,非常小的数据集和小对象的性能会更好.如果您在大型数据集中讨论查找,其中您将对象用作映射,则对象更有效.http://jsperf.com/array-vs-object-performance/35 (9认同)
  • 同意f1v,但修订版35在测试中有一个缺陷:`if(a1 [i] .id = id)result = a1 [i];`应该是:`if(a1 [i] .id === id )result = a1 [i];`测试[http://jsperf.com/array-vs-object-performance/37](http://jsperf.com/array-vs-object-performance/37)纠正了 (5认同)
  • 通过在本文中总结jsPerf结论可以改进这个答案 - 特别是因为jsPerf结果是问题的真正答案.其余的是额外的.当jsPerf关闭时(比如现在),这更为相关.http://meta.stackexchange.com/questions/8231/are-answers-that-just-contain-links-elsewhere-really-good-answers (4认同)
  • 测试有问题。现实中的“数组”方法并没有那么慢。**首先**,在生成元素时,`o` 和`a2` _仅在它们还没有的情况下获得一个新元素_,而一个新元素被推入`a1` _总是_。如果它两次生成相同的数字,它不会被添加到 `o` 和 `a2` 中,而是会被推送到 `a1` 中。不太可能,但仍然...... **其次**,在`a1`的测试中,任何正常人一旦找到项目就会打破循环......这显着改变了结果。[自己检查](http://jsben.ch/j9X4n)。 (2认同)

dec*_*eze 23

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

如果您尝试在数组上设置任意(数字)键,则确实会导致性能下降,因为在行为上,数组将填充中间的所有索引:

> foo = [];
  []
> foo[100] = 'a';
  "a"
> foo
  [undefined, undefined, undefined, ..., "a"]
Run Code Online (Sandbox Code Playgroud)

(请注意,数组实际上并不包含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
Run Code Online (Sandbox Code Playgroud)

  • 但我想知道什么是更好的表现:从数组中检索对象(通过循环遍历)或从id为关键字的"关联"对象.如果我的问题不明确,我很抱歉...... (5认同)
  • @Moshe如果您通过键访问对象或数组中的任何内容,它总是比遍历容器尝试查找所需内容快得多。通过键访问数组或对象中的项的差异可能微不足道。循环显然更糟。 (2认同)

san*_*rom 14

使用ES6,最高效的方法是使用Map.

var myMap = new Map();

myMap.set(1, 'myVal');
myMap.set(2, { catName: 'Meow', age: 3 });

myMap.get(1);
myMap.get(2);
Run Code Online (Sandbox Code Playgroud)

您现在可以使用垫片(https://github.com/es-shims/es6-shim)使用ES6功能.

性能将根据浏览器和方案而有所不同.但这里有一个Map高效的例子:https://jsperf.com/es6-map-vs-object-properties/2


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

  • 有资源支持吗?从我的观察到目前为止,ES6集比数组快,但ES6映射比对象和数组都慢 (9认同)
  • @AlexG非常确定标题清楚地表明了"效率". (3认同)

Paw*_*weł 6

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');
Run Code Online (Sandbox Code Playgroud)

结果:

Array result:
arrTimer: 12.857ms
Object result:
objTimer: 0.051ms
Run Code Online (Sandbox Code Playgroud)

即使搜寻ID是阵列/物件中的第一个ID:

Array result:
arrTimer: 2.975ms
Object result:
objTimer: 0.068ms
Run Code Online (Sandbox Code Playgroud)


Dav*_*m M 5

从字面上看,我试图将其扩展到下一个维度。

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

a)通过创建一个二维数组并查找第一个索引,然后查找第二个索引来查找单元格,即:

var arr=[][]    
var cell=[x][y]    
Run Code Online (Sandbox Code Playgroud)

要么

b)创建一个具有x和y坐标的字符串表示形式的对象,然后对该obj进行一次查找,即:

var obj={}    
var cell = obj['x,y']    
Run Code Online (Sandbox Code Playgroud)

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

结果在这里:

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