首先要说明的是,这个命题是不完整的,应该说是特定条件下倒序循环优于正序循环。
在解决这个疑问前,我们先做几个小实验来证明一些事情:
1.数值大小对计算加减法速度的影响
let number = 1000000000
console.time()
for (let i = 0; i<10001;i++) {
number-=1
}
console.timeEnd()
由以上一段简单的代码,我分别设置了10w与一亿(数值过小没测试意义,计算机性能的波动范围都可能大于计算它的时间),各执行十次的结果为:
十万: 0.3、0.29、0.31、0.33、0.27、0.28、0.28、0.42、0.3、0.27
一亿:0.42、0.31、0.34、0.41、0.48、0.42、0.41、0.44、0.3、0.41
结论:十万的计算速度明显优于一亿
ps:四舍五入取小数点后两位,单位ms
2.for循环的终止条件是如何执行的
我们都知道,for循环包含三个要素——声明变量(起始),终止条件,以及递增递减(忘了这个该叫啥,懂就好了)。那么大家有没有想过,在整个循环过程中,各个要素都是怎样执行的呢?话不多说,一段简单代码验证下:
// 这个函数用来验证是否被使用
function number() {
console.log('我被调用了')
return 100000
}
//-------------- 分割线 ------------------
for (let i = number(); i<0;i--) {
}
// 以上代码,控制台打印了一次‘我被调用了’
for (let i = 0; i< number();i++) {
}
// 以上代码,控制台打印了100000次‘我被调用了’
结果很明显,声明变量阶段,赋值过一次后,后续循环都不会反复的调用number方法了。而终止条件则需要每次都去调用number方法。
3.获取数组长度与获取数值大小的速度问题
这个没什么说的,直接代码试验下,我进行了长度为100万的数组,与100万的数值的比较。测试代码如下:
let n
let array = new Array(100000)
console.time()
for (let i = 0; i<10001;i++) {
n=array.length
}
console.timeEnd()
// -------------------- 分割线 -------------------------
let n
let number = 100000
console.time()
for (let i = 0; i<10001;i++) {
n=array.length
}
console.timeEnd()
记录过程就不写了,有兴趣可以自己跑跑,结论是获取数值比获取数组长度快。
基于以上验证的三点,相信大家应该已经知道了为什么for循环数组倒序快于正序了,但我还是总结下。
倒序并不是快于正序,之所以我们看到的倒序更快,是因为写法原因导致的,通常我们正序会直接把array.length直接写进终止条件里,而倒序则是写在变量声明阶段。这样既验证了试验2的结论,也验证了试验3的结论。所以这种情况下倒序快于正序。
ps:其实明白这些,在今后的一些数组操作中,如果循环体里没有改变数组长度的操作,正序可也以靠一些手段优化,比如先把length赋值给一个变量,这样就不会在终止条件中反复求数组长度。