Object.keys() 复杂度?

IT技术 javascript performance time-complexity ecmascript-5
2021-03-05 12:33:20

有人知道 ECMAScript5 的 Object.keys() 在常见实现中的时间复杂度吗?O(n)为了n钥匙吗?假设哈希实现,时间是否与哈希表的大小成正比?

我正在寻找语言实现者的保证或一些现实世界的基准测试。

2个回答

它似乎O(n)至少在 V8(chrome、node.js)中:

> var hash = {}
>   ,    c = 0;
> 
> var s = +new Date();Object.keys(hash);console.log(+new Date() - s);
0
> for(var i=0; i<100000; i++, c++){ hash[c] = 1; }
> var s = +new Date();Object.keys(hash);console.log(+new Date() - s);
26
> for(var i=0; i<100000; i++, c++){ hash[c] = 1; }
> var s = +new Date();Object.keys(hash);console.log(+new Date() - s);
49
> for(var i=0; i<100000; i++, c++){ hash[c] = 1; }
> var s = +new Date();Object.keys(hash);console.log(+new Date() - s);
75
> for(var i=0; i<100000; i++, c++){ hash[c] = 1; }
> var s = +new Date();Object.keys(hash);console.log(+new Date() - s);
102    
@hurrymaplead - 什么?所有 JS 哈希键都是字符串。这段代码有效地生成{'1':1, '2':1, '3':1, ...} 稀疏密集键对哈希实现没有意义,只有数组。对于引擎来说,将散列实现为数组确实没有任何意义,因为数字索引通常相当罕见。但是,如果您出于某种原因想对其进行测试,只需更改c++c+=Math.random()which 将为您提供完全不可关联的键。
2021-04-20 12:33:20
@cwolves:Array对象只是一个对象,其属性应为整数。这些并不少见,而且肯定有使用数组来支持Array实例的JS 实现
2021-04-26 12:33:20
@cwolves:扩展您的测试以涵盖密钥大小大小的变化,并且结果看起来一致。您说得对,稀疏与密集不适用于您的测试。我正在寻找一个具有低负载系数的示例,但这与关键选择无关。JS 对象通常是作为哈希图实现的吗?如果是这样,性能O(n+s)s哈希表的大小在哪里
2021-04-29 12:33:20
这些结果对于密集哈希图是有意义的。随着键变得越来越稀疏,性能是否会下降?
2021-04-30 12:33:20
JS 对象不是作为哈希映射实现的,而是作为数组对(即 C 数组,而不是 JS 数组对象)实现的code.google.com/intl/de-DE/chrome/devtools/docs/...
2021-04-30 12:33:20

(此处为 V8 开发人员。)

Mark Kahn 的答案对于足够密集的整数键控/“索引”属性是正确的,其中 的复杂度Object.keys()确实是 O(n)。

虽然 JavaScript 规范假设所有对象属性都是字符串键控/“命名”的,但这并不是现代高性能引擎实现它的方式。内部差别很大!索引属性被存储在一个阵列(只要它们是足够密集),这给了通常更好的性能比{'1': 1, ...}字典会。

对于具有数千个命名属性的对象,我们的实现确实使用了一个哈希表(正如问题所猜测的那样),这意味着复杂度Object.keys()为 O(n log n)那是因为哈希表(当然)按自己的顺序存储条目。Object.keys()必须按照它们创建的顺序返回命名属性,我们将其存储为附加元数据,这意味着我们必须在从哈希表中检索键后对键进行排序,这是一个 O(n log n) 操作。

在实践中出现的大多数对象上的命名属性(最多大约一千个属性)(通常)以创建顺序存储在一种特殊类型的内部数组中,因此它们可以在 O(n) 中检索并且不需要排序。

所以总结真的是“视情况而定”:-)

@DaveAnkin:如果有那么简单,我会这么说的。没那么简单。它会随着时间/版本/实现而变化。这通常也无关紧要:对于大多数常见情况,假设Object.keys()具有线性复杂性是合理的(即使并非在所有情况下都如此)。请注意,“来自其他答案的代码”仅说明了一种特殊情况,而不是所有可能的情况。
2021-04-30 12:33:20
嗯,但这里的问题是,如果我使用 an ,Object.keys()它会是 anO(n)还是其他什么?我没有完全理解你的答案......用天真的术语来说,如果我有一个如下的哈希图:{a:1,b:2,...}并且我使用Object.keys()它,时间复杂度是O(n)还是其他的?另外,如果我们只想获取密钥而不是对它们进行排序怎么办?
2021-05-01 12:33:20
@jmrk 当然,没有一个基准是完美的(我添加了 Math.random().toString(16).substring(2) 以获得更长的键),但是对于 object<string, string> 20 似乎是原海报要求)
2021-05-02 12:33:20
不排序就无法获得对象的键。正如我所写的, 的复杂度Object.keys()是 O(n) 还是其他取决于您对象的细节(当然,还取决于您碰巧运行的特定 JavaScript 引擎的特定版本的实现细节)。没有任何保证。
2021-05-07 12:33:20
截止值为 20,您可以使用其他答案中的代码并使用非常小的对象进行验证,但多次调用 Object.keys
2021-05-08 12:33:20