这里有新鲜出炉的 Javascript 教程,程序狗速度看过来!
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
这篇文章主要介绍了 JavaScript 中 for 循环的效率问题及相关优化, 文中谈到了 Underscore.js 库及循环在各个浏览器 js 解释器下的表现, 需要的朋友可以参考下
Underscore.js 库
你一天(一周)内写了多少个循环了?
- var i;
- for(i = 0; i < someArray.length; i++) {
- var someThing = someArray[i];
- doSomeWorkOn(someThing);
- }
这当然无害,但这种写法非常丑而且奇怪,这也不是真正需要抱怨的。但这种写法太平庸了。
- 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),我的代码更容易理解。 怎么做的呢?
- _.each(someArray, function(someThing) {
- doSomeWorkOn(someThing);
- })
或者更好一点:
- _.each(someArray, doSomeWorkOn);
这就是 underscorejs 所做到的。干净,简单,易读,短,没有中间变量,没有成堆的分号,简单非常优雅。 这是另外一些例子。
- var i,
- result = [];
- for(i = 0; i < someArray.length; i++) {
- var someThing = someArray[i];
- // 打到这,我已经手疼了
- if(someThing.isAwesome === true) {
- result.push(someArray[i]);
- }
- }
同样,一个使用循环浪费时间的典型用例。即便这些网站是宣传禁烟和素食主义的,看到这些代码我也感到义愤。看看简单的写法。
- var result = _.filter(someArray, function(someThing) {
- return someThing.isAwesome === true;
- })
像 underscore 中的 filter(过滤)的名字那样,随手写的 3 行代码就可以给你一个新的数组(array)。 或者你想把这些数组转换成另外一种形式?
- var result = _.map(someArray, function(someThing) {
- return trasformTheThing(someThing);
- })
上面三个例子在日常生活中已经够用了,但这些功能还不足矣让 underscore 放到台面上。
- 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 版本
- 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 原生方法写的例子:
- [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 每次都会重新计算数组长度,因此通常用临时变量来事先存储数组长度,如:
- for (var idx = 0, len = testArray.length; idx < len; idx++) {
- //do sth.
- }
我们也会测试一下缓存与不缓存时的性能差异。
同时在每个测试循环中添加求和运算,来表明其不是空循环。
- for (var idx = 0, len = testArray.length; idx < len; idx++) {
- //do sth.
- }
我们也会测试一下缓存与不缓存时的性能差异。
同时在每个测试循环中添加求和运算,来表明其不是空循环。
测试代码如下,点击运行即可查看 html 代码
- <h4 id="browser">
- </h4>
- <table id="results" class="table">
- </table>
JavaScript 代码
- 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 三者测试结果拼接的一张汇总。
以下是几个观察到的结论
来源: http://www.phperz.com/article/17/0404/266708.html