JavaScript中for循环的效率对比

http://www.jb51.net/article/80854.htm


Underscore.js库

你一天(一周)内写了多少个循环了?

?
1
2
3
4
5
var i;
for (i = 0; i < someArray.length; i++) {
  var someThing = someArray[i];
  doSomeWorkOn(someThing);
}

这当然无害,但这种写法非常丑而且奇怪,这也不是真正需要抱怨的。但这种写法太平庸了。

?
1
2
3
4
5
6
7
8
var i,
  j;
for (i = 0; i < someArray.length; i++) {
  var someThing = someArray[i];
  for (j = 0; j < someThing.stuff.length; j++) {
    doSomeWorkOn(someThing.stuff[j]);
  }
}

你在扩展糟糕的代码,在你抛出一大堆if前,你已经精神错乱了。
我在两年里没有写一个循环(loop)。
“你在说什么?”
这是真的,一个冷笑话。其实不是一个都没有(好吧,我确实写了几个),因为我不写循环(loops),我的代码更容易理解。
怎么做的呢?

?
1
2
3
_.each(someArray, function (someThing) {
  doSomeWorkOn(someThing);
})

或者更好一点:

?
1
_.each(someArray, doSomeWorkOn);

这就是underscorejs所做到的。干净,简单,易读,短,没有中间变量,没有成堆的分号,简单非常优雅。
这是另外一些例子。

?
1
2
3
4
5
6
7
8
9
var i,
  result = [];
for (i = 0; i < someArray.length; i++) {
  var someThing = someArray[i];
  // 打到这,我已经手疼了
  if (someThing.isAwesome === true ) {
    result.push(someArray[i]);
  }
}

同样,一个使用循环浪费时间的典型用例。即便这些网站是宣传禁烟和素食主义的,看到这些代码我也感到义愤。看看简单的写法。

?
1
2
3
var result = _.filter(someArray, function (someThing) {
  return someThing.isAwesome === true ;
})

像underscore中的filter(过滤)的名字那样,随手写的3行代码就可以给你一个新的数组(array)。
或者你想把这些数组转换成另外一种形式?

?
1
2
3
var result = _.map(someArray, function (someThing) {
  return trasformTheThing(someThing);
})

上面三个例子在日常生活中已经够用了,但这些功能还不足矣让underscore放到台面上。

?
1
2
3
4
5
6
7
8
var grandTotal = 0,
  somePercentage = 1.07,
  severalNumbers = [33, 54, 42],
  i; // don't forget to hoist those indices;
for (i = 0; i < severalNumbers.length; i++) {
  var aNumber = severalNumbers[i];
  grandTotal += aNumber * somePercentage;
}

underscore版本

?
1
2
3
4
5
6
var somePercentage = 1.07,
  severalNumbers = [33, 54, 42],
  grandTotal;
grandTotal = _.reduce(severalNumbers, function (runningTotal, aNumber) {
  return runningTotal + (aNumber * somePercentage);
}, 0)

这个刚开始看上去可能有点怪,我查了下关于reduce的文档,知道了它的存在。因为我拒绝使用循环,所以它是我的首选。上面这些东西仅仅是入门,underscorejs库还有一大堆牛B的功能。

30天不使用循环的挑战。

在一下一个30天里,不要使用任何循环,如果你看到一堆讨厌和粗糙的东西,用each或者map将他们替换掉。再用一点reducing。

你需要注意到,Underscore是通往函数式编程的。一种看得见,看不见的方式。一条很好的途径。


OurJS注*目前现代浏览器已经支持each, filter, map, reduce方法,但underscore库可以实现对旧版IE的兼容,下面是使用ES5原生方法写的例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[3,4,5,3,3].forEach( function (obj){
   console.log(obj);
});
 
[1,2,3,4,5].filter( function (obj){
   return obj < 3
});
 
[9,8,5,2,3,4,5].map( function (obj){
   return obj + 2;
});
 
[1,2,3,4,5].reduce( function (pre, cur, idx, arr) {
   console.log(idx);  //4 个循环: 2-5
   return pre + cur;
});  //15
 
//sort方法同样很有用
[9,8,5,2,3,4,5].sort( function (obj1, obj2){
   return obj1 - obj2;
});

for in与for loop

有人提出for in的效率要比for loop(循环)的效率低非常多。现在我们测试一下在不同浏览器中使用for in, for loop和forEach在处理大数组时的效率究竟如何。

目前绝大部分开源软件都会在for loop中缓存数组长度,因为普通观点认为某些浏览器Array.length每次都会重新计算数组长度,因此通常用临时变量来事先存储数组长度,如:

?
1
2
3
for ( var idx = 0, len = testArray.length; idx < len; idx++) {
  //do sth.
}

我们也会测试一下缓存与不缓存时的性能差异。

同时在每个测试循环中添加求和运算,来表明其不是空循环。

?
1
2
3
for ( var idx = 0, len = testArray.length; idx < len; idx++) {
  //do sth.
}

我们也会测试一下缓存与不缓存时的性能差异。

同时在每个测试循环中添加求和运算,来表明其不是空循环。

测试代码如下,点击运行即可查看
HTML 代码

?
1
2
< h4 id = "browser" ></ h4 >
< table id = "results" class = "table" ></ table >

JavaScript 代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
function () {
 
  //准备测试数据, 有200万条数据的大数组
  var testArray = []
   , testObject = {}
   , idx
   , len = 2000000
   , tmp = 0
   , $results = $( "#results" )
   , $browser = $( "#browser" )
   ;
 
  $browser.html(navigator.userAgent);
  $results.html( '' );
 
  for ( var i = 0; i < len; i++) {
   var number = Math.random(); //若希望加快运算速度可使用取整:Math.random() * 10 | 0
   testArray.push(number);
   testObject[i] = number;
  }
 
  $results.append( '<tr><th>测试代码</th><th>计算结果</th><th>所需时间,毫秒</th></tr>' );
 
  //测试函数
  var test = function (testFunc) {
   var startTime
    , endTime
    , result
    ;
 
   startTime = new Date();
   tmp = 0;
   testFunc();
   endTime  = new Date();
 
   //计算测试用例(Test Case)运行所需要的时间
   result = endTime - startTime;
   $results.append( '<tr><td><pre>{0}</pre></td><td>{1}</td><td>{2}</td></tr>' .format(testFunc.toString(), tmp | 0, result));
  };
 
 
  test( function () {
   //测试for in 的效率
   for (idx in testArray) {
    tmp += testArray[idx]; //经测试,idx是string类型,可能是慢的原因之一
   }
  });
 
  test( function () {
   //测试for loop循环的效率
   for (idx = 0, len = testArray.length; idx < len; idx++) {
    tmp += testArray[idx];
   }
  });
 
  test( function () {
   //测试forEach的效率
   testArray.forEach( function (data) {
    tmp += data;
   });
  });
 
  test( function () {
   //测试不缓存Array.length时效率
   for (idx = 0; idx < testArray.length; idx++) {
    tmp += testArray[idx];
   }
  });
 
  test( function () {
   //测试使用{} (Object) 存健值对时,使用for in的效率如何
   for (idx in testObject) {
    tmp += testObject[idx];
   }
  });
  
  test( function () {
   //测试从{} Object查值时的效率如何(这里的健key值事先己知)
   for (idx = 0, len = testArray.length; idx < len; idx++) {
    tmp += testObject[idx];
   }
  });
 
}

运行 [需稍等片刻]
测试结果
测试结果可能因计算而异,这是在我机器上运行用,Firefox, Chrome, IE三者测试结果拼接的一张汇总。

2016313110044207.jpg (971×678)

以下是几个观察到的结论

  • for in比for loop慢非常多,在Chrome中至少慢20倍
  • FF对forEach(ES5)做了优化,性能比for loop还要好一点,但Chrome/IEn性能均较差
  • FF/Chrome缓存Array.length均比直接用时要慢一点。除IE最新版缓存后性能提升微乎其微(这一点非常意外)
  • 在某些情况下,FF的JS引擎性能似乎比V8要好些
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值