让我们假设我们应该得到一些数据......
var data = [];
//some code omitted that might fill in the data (though might not)
然后我们需要对数据做些什么。我的问题是如何更有效地做到这一点。 像这样?:
if (data.length) {
for (var i = 0; i < data.length; i++) {
//iterate over the data and do something to it
}
}
还是这样?:
for (var i = 0; i < data.length; i++) {
//iterate over the data and do something to it
}
关键是在迭代之前是否检查长度?
答案 0 :(得分:8)
我认为不值得检查是否根据for
的{{1}}执行length
循环,因为如果{data
可能会在性能方面没有太大差异{1}}循环只执行几次。
但一般来说,首先获得长度而不是将其设置为for
会更快,因为每次都需要访问变量。至于哪种方式最有效地循环数据,不同的浏览器针对不同类型的循环进行了优化。但是,它只是认真慢的IE(在下面的测试中比其他浏览器慢几个数量级)所以我认为优化其他浏览器可能不值得。
以下是基准测试的结果(最快用+表示,最慢用 - 表示):
FF Chrome Safari Opera IE6 IE7 IE8 Method 1 +0.163+ 0.221 0.246 0.269 -11.608- -12.214- -7.657- Method 2 0.175 +0.133+ 0.176 +0.147+ 8.474 8.752 3.267 Method 3 0.206 0.235 0.276 0.245 8.002 8.539 3.651 Method 4 0.198 0.372 0.447 0.390 +6.562+ +7.020+ 2.920 Method 5 0.206 0.372 0.445 -0.400- 6.626 7.096 +2.905+ Method 6 0.176 0.167 +0.175+ 0.223 7.029 8.085 3.167 Method 7 -0.263- -0.567- -0.449- 0.413 6.925 7.431 3.242
方法1:使用“标准”i<data.length
循环:
for
方法2 :使用“标准”for (var i=0; i<data.length; i++) {
var x = data[i]
}
循环,分配for
,使其不必每次都可以访问:
length
方法3:这类似于jQuery在for (var i=0, len=data.length; i<len; i++) {
var x = data[i]
}
中使用的方法。请注意分配给$.each()
,这样就不必每次都获得len
。
length
方法4:使用for (var x=data[0], len=data.length, i=0; i<len; x=data[++i]) {}
循环,前进。 警告:需要数组中的每个项目评估为while
,即不是true
,false
,0
,null
, undefined
等等!
''
方法5:与方法4相同,仅使用var x, i=0
while (x = data[i++]) {}
执行相同操作:
for
方法6:使用for (var x,i=0; x=data[i++];) {}
向后循环:
while
方法7 :使用方法4 /方法5,但无需将项目评估为var i = data.length
while (i--) {
var x = data[i]
}
,替换true
:
x = data[i++]
首先检查var x, i=0, len=data.length
while ((x=data[i++]) || i<len) {}
是否评估为data[i++]
,然后检查它是否是最后一项,以便在IE中具有相似的性能,true
和null
等问题更少在数组中。请注意,在这种情况下使用false
vs while
时没有明显的差异,但我更喜欢for
因为我认为它更清楚。
我通常不喜欢优化,除非有一个特定的长期运行任务,因为它往往以可读性为代价 - 请只有在你有一个特定的案例,你有大量的数据来执行它加载等: - )
编辑:由于方法4/5在IE上速度如此之快,因此添加了副作用较少的版本。
编辑2:重做所有测试,这次没有任何浏览器扩展且更长时间。这是为了完整起见的代码(抱歉这篇文章很长:)
while
答案 1 :(得分:4)
我认为第二个版本更具惯用性,不仅仅是在JavaScript中,而是在大多数编程语言中。如果您关心时序,可以将数组的长度保存在变量中,并在循环中使用该变量,但我不认为这是必要的:
var data = [];
var length = data.length;
for (var i = 0; i < length; i++) {
//iterate over the data and do something to it
}
答案 2 :(得分:2)
检查data.length并迭代它需要什么?
只需使用for循环即可。
答案 3 :(得分:2)
我通常不会在迭代前检查长度。事实上,for循环本身将检查每次迭代的长度。
没有值得一提的性能开销。在长度为0的情况下,唯一的额外指令是将在内存中声明新的int。你需要成千上万的人才能感受到毫秒的影响。
答案 4 :(得分:1)
如果数据没有项目,那么data.lenght将为0.因此,你的循环永远不会触发,因为i = 0已经小于数组中的项目数。因此,选项2很好。
但是,在执行托管代码时,您可能希望在对该对象调用.length之前检查NULL对象。
答案 5 :(得分:1)
我认为在这种情况下循环data
的最有效方法是:
var pos = data.length;
while (pos--) {
// do something to => data[pos]
}
,尽可能减少查找和声明。 它将向后迭代这些项目,但这可能并不总是令人担忧。