问题是 Set.has() 方法 O(1) 和 Array.indexOf O(n) 吗?被列为此副本的副本,但并不完全正确(我已投票决定重新开放)。无论如何,我将在此处添加这些基准,因为对该问题的答复中的基准未能显示Set#has
和之间的全部性能差异Array#indexOf
。
以下内容适用于 Chrome 93:
您会发现对于较小的数据集,Array#indexOf
实际上优于Set#has
或Map#has
; 然而,对于更大的数据集,Set#has
并Map#has
有多个数量级快。这与您对 O(n) 与 O(1) 操作的期望非常一致。
有趣的是,尽管两者都是 O(n),Array#includes
但比Array#indexOf
小数据集慢得多,但对大数据集的表现非常相似。据推测,Array#indexOf
利用了一些Array#includes
没有的优化。
同时,Object#hasOwnProperty
略微优于Set#has
以及Map#has
在所有情况下(至少在Chrome 93)。
基准代码
const [small, medium, large] = [1e3, 1e5, 1e7]
const configs = [
{ size: small, iterations: large },
{ size: medium, iterations: medium },
{ size: large, iterations: small },
]
for (const { size, iterations } of configs) {
const arr = Array.from({ length: size }, (_, i) => String(i))
const obj = Object.fromEntries(arr.map(k => [k, true]))
const set = new Set(arr)
const map = new Map(Object.entries(obj))
const valsToTest = Array.from(
{ length: iterations },
(_, i) => String(Math.floor(Math.random() * size)),
)
const title = `dataset size: ${size.toLocaleString()}; iterations: ${iterations.toLocaleString()}`
console.log(`\n-> ${title}`)
for (const [target, method] of [
[arr, 'indexOf'],
[arr, 'includes'],
[set, 'has'],
[map, 'has'],
[obj, 'hasOwnProperty'],
]) {
const subtitle = `${target.constructor.name}#${method}`
console.time(subtitle)
for (const val of valsToTest) {
target[method](val)
}
console.timeEnd(subtitle)
}
}
我的结果(Chrome 93)
-> dataset size: 1,000; iterations: 10,000,000
Array#indexOf: 185.100ms
Array#includes: 11302.700ms
Set#has: 367.400ms
Map#has: 375.000ms
Object#hasOwnProperty: 252.800ms
-> dataset size: 100,000; iterations: 100,000
Array#indexOf: 10794.100ms
Array#includes: 10476.800ms
Set#has: 6.600ms
Map#has: 6.800ms
Object#hasOwnProperty: 1.900ms
-> dataset size: 10,000,000; iterations: 1,000
Array#indexOf: 12798.900ms
Array#includes: 12435.400ms
Set#has: 0.800ms
Map#has: 0.800ms
Object#hasOwnProperty: 0.300ms