为什么循环通过一个数组比JavaScript本地`indexOf`快得多?

为什么循环访问Array比JavaScript本地indexOf快得多? 有没有错误或我没有考虑的东西? 我预计本地实施会更快。

  For Loop While Loop indexOf Chrome 10.0 50,948,997 111,272,979 12,807,549 Firefox 3.6 9,308,421 62,184,430 2,089,243 Opera 11.10 11,756,258 49,118,462 2,335,347 

http://jsben.ch/#/xm2BV

5年后,浏览器发生了很多变化。 现在,indexOf的性能已经提高了,绝对比其他的定制select更好。

版本49.0.2623.87(64位)

Chrome版本49.0.2623.87(64位)

可能是因为实际的indexOf实现比循环遍历数组要多得多。 你可以在这里看到Firefox的内部实现:

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf

有几件事情可以减缓循环,为了理智的目的:

  • 该数组正在重新转换为Object
  • fromIndex正被转换为数字
  • 他们使用Math.max而不是三元组
  • 他们使用Math.abs

indexOf做了一堆for循环和while循环忽略的types检查和validation。

这里是indexOfalgorithm:

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf

编辑:我的猜测是indexOf是大数组更快,因为它在循环之前caching数组的长度。

再次运行testing与我做的编辑。

我已经增加了数组的大小,并且让你search的索引也变大了。 在大数组中,indexOf可能是更快的select。

http://jsben.ch/#/xm2BV

编辑:基于更多的testing,indexOf似乎比在我使用的Safari版本(5.0.3)中的for循环运行得更快,而在其他所有方面都比较慢。

值得注意的是,如果你所要做的只是保存一个项目列表并检查是否存在(例如,避免将重复的ID添加到数组中),那么使用反映每个ID的密钥保持对象的速度要快得多。 如果你认为我错了,比较下面的数组+ indexOf。 对于数组indexOf方法,我们正在讨论181ms的对象方法和1分钟的MINUTE。

 var objs = [] var i_uid = {} // method 1 var a_uid = [] // method 2 var total_count = 100000, idLen = 5 var ts, te, cObj = 0 // method 1 ts = new Date() while (cObj < total_count) { var u = uid(idLen), o = { uid: u, text: 'something', created: new Date() } if (!i_uid[u]) { // ensure unique uids only objs.push(o) i_uid[u] = cObj // current array position as placeholder cObj++ } else { console.log('unique violation [duplicate uid', u, ']') } } te = new Date() console.log('loaded ' + total_count + ' with object method in', (te - ts), 'ms') i_uid = {} // free-up cObj = 0 // reset objs = [] // reset // method 2 ts = new Date() while (cObj < total_count) { var u = uid(idLen), o = { uid: u, text: 'something', created: new Date() } if (a_uid.indexOf(u) == -1) { // ensure unique uids only objs.push(o) a_uid.push(u) cObj++ } else { console.log('unique violation [duplicate uid', u, ']') } } te = new Date() console.log('loaded ' + total_count + ' with array + indexOf method in', (te - ts), 'ms') function uid(l) { var t = '', p = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', pl = p.length for (var i = 0; i < l; i++) t += p.charAt(Math.floor(Math.random() * pl)) return t } 

我们可以信任每一次平原循环。

我写了下面的代码来发现这个问题的答案。 它也可以运行 。 它表明,在考虑性能时,plain for loop是最好的解决scheme。

(代码也可以在jsfiddle上find )

 console.clear() let a = [] // populating array data for (let i = 0; i < 100000; i++) { a.push(i) } let testNum = 90000 let found let totalMS4ForLoop = 0 let totalMS4IndexOf = 0 let start let end // simulating 10000 requests which are come consecutively for (o = 0; o < 10000; o++) { start = Date.now() for (let i = 0; i < a.length; i++) { if (a[i] == testNum) { found = a[i]; break } } end = Date.now() totalMS4ForLoop += end - start start = Date.now() found = a[a.indexOf(testNum)] end = Date.now() totalMS4IndexOf += end - start } console.log("10000 for-loop executions took total " + totalMS4ForLoop + " ms.") console.log("10000 indexOf executions took total " + totalMS4IndexOf + " ms.")