优化迴圈与判断式让JavaScript更加优美的小撇步

破坏之王

「我要努力向上,不付诸君期望」 ~整人专家-胡真~

就前端初学者的思维,大多会把「写出可以运行的 code 」当作是练习或是实作的终极目标,而美化 code 内容或是使其运行效率更快什么的,等到实力累积到一定程度之后在来处理就好。(好吧也有可能只有我是这样想http://img2.58codes.com/2024/emoticon02.gif)
但其实世界是美好的~有些优化的关键其实只是透过一些基础概念的运用便可达成,不需要多艰深的知识就能使用自如,本篇就以 JavaScript 中常会使用的判断式(judgment)与迴圈(loop)为例,透过一些使用上的小诀窍让 code 更加美化~

一. if 与 switch 的使用时机

身为 JavaScript 判断式的两本柱,switch 真的是存在感渺小的可怜,因为 if 的自由度跟弹性真的是比 switch 来得强大许多,但其实 switch 也没那么不堪,有些时候派他上场反而能使 code 更加美观而且不会妨碍运行效力喔!
举个例子,当今天有一个栏位要请使用者填入 1~n,然后依照填入的各种数字有对应的功效,使用 if 的话应该会写成:

var input_number = 输入数字 if(input_number === '1'){    console.log('子瑜我婆');}else if(input_number === '2'){    console.log('初音我婆');}else if(input_number === '3'){        ......        ......}else{    console.log('全都是我婆');}

当填入的数字越多,要键入的 input_number 次数就越多,虽然有複製贴上但也是挺麻烦的,而且画面也因为夹杂许多不同种类的括弧而有些杂乱,此时只要使用被遗忘的 switch :

var input_number = 输入数字 switch(input_number){    case '1':        console.log('子瑜我婆');        break;    case '2':        console.log('初音我婆');        break;        ......        ......    default:        console.log('全都是我婆');}

比较一下两边的内容,switch 版本是不是比较漂亮一些呢~这边补充一个微知识,switch 是使用全等模式判断(就是 if 中的三个等号),所以在上面的範例,千万不能写成 case 1: 这样,不然就会直接走 default 分支喔!

二. 三目运算子(三元运算子/条件运算子)

相信有不少新手在自学时,上网拜读各个大神的文章时,时常会看到 code 中判断式夹杂着 ? 与 : 的语句,看到的当下肯定是满脑子问号,其实这就是大名鼎鼎的三目运算子,公式如下:

//使用 if 判断式if(target){    //当目标为 True 时的答案}else{    //当目标为 False 时的答案}//使用三目运算子(target) ? (//当目标为 True 时的答案) : (//当目标为 False 时的答案)

上面可以看到,使用三目运算子可以将五行的 code 缩减成一行结束,真的简单有力又省时~以下举几个例子:

//如果考试前有拜春哥及关帝则可上榜,否则落榜拜春哥||拜关帝 ? 上榜 : 落榜;//三目运算子也可以运用到 jquery 上//当 target 为 True 时使用 addClass 方法,False 时则使用 removeClass target ? $('body').addClass('子瑜') : $('body').removeClass('子瑜');//将上面的 code 昇华一下$('body')[target ? 'addClass' : 'removeClass']('子瑜');//套用在function上function a(){....}function b(){....}target ? a() : b();

三. return 的美妙之处

在判断式中,return 常用来返回达成目标对应之值,但其实 return 同时也会终止函式的执行,所以活用 return 则可以减少 if else 的使用,使 code 更加美观,像是下面的例子:

//当搜寻栏按下enter时才会进行动作,当搜寻栏为空值则 alert('栏位不得空白')//一般写法searchbar.addEventListener('keyup', function(e){    if(e.keyCode === '13'){        if(this.value === ''){            alert('栏位不得空白');        }else{            //搜寻动作        }    }}  //活用return的写法searchbar.addEventListener('keyup', function(e){    if(!e.keyCode === '13'){        return;    }    if(this.value === ''){        alert('栏位不得空白');        return;    }    //搜寻动作}//更简洁的写法searchbar.addEventListener('keyup', function(e){    if(!e.keyCode === '13') return;    if(this.value === '') return alert('栏位不得空白');    //搜寻动作}

上面的例子可以看出活用 return 可以减少巢状的写法,使 code 简洁有力,真的是个神奇的小东西~

四. for 陈述式/for in/forEach/for of的效能比较

讲完了判断式的优化撇步,也来谈谈迴圈吧!迴圈最常被用到的就是 for-loop 了,而 for 迴圈也有百百中,各种都有不同的美妙跟运行能力,关于这些用法执行的效率测试估狗大神已经满多都有实作的,本篇就直接破题统整各种 for-loop 的效能与用途(想看效能实测的人可以看这篇)
类型 | 效能 | 推荐使用地方 | 参考
------------- | ------------- | -------------
for陈述式 | 效能最高 | 其实一般使用都建议用此方法,但写法有些繁琐 | 参考连结
for in | 效能最低(需要历遍对象的所有属性) | 运行耗时最久,类似forEach但可作用在 object 跟 array 上 | 参考连结
forEach | 效能中间 | 目标为 array 时推荐使用,写法简单清楚速度又不算慢 | 参考连结
for of | 效能中间(略高于 forEach) | 属于 ES6 的语法,其写法简洁有力,兼具 for in 的优点又避开其所有缺陷,与 forEach不同的是,此语法可响应 break、return、continue等语句 | 参考连结

五. 让 for-loop 更加有效率吧!

除了透过活用上面各种 for-loop 的语法外,也可以透过一些小技巧来使迴圈运行更有效率喔!
1. 减少迭代的工作量
我们拿两个例子来做比较

//Case Afor(var i = 0; i < target.length; i++){      //迭代内容;  }  //Case Bfor(var i = 0,len = target.length; i < len; i++){      //迭代内容;   }  

上面两个案例都可以达到相同的目标,但 CaseA每迭代一次就需要计算一次 target 的长度,累加下来会比 CaseB耗费更多的时间,所以如果迴圈中有已知的参数,尽量在迴圈外就将其定义,则可减少迴圈迭代的工作量。
这边补充一个微知识,如果无关迭代的运算也别放在迴圈内喔,不然也会增加迴圈工作量(虽然能减少 code 的行数,好像是有达到美观效果)。
2. 降低迭代的次数
就算是一个再有效率的 code ,当迭代次数过多时,还是会受其影响而使 运行效能降低,如果能在迴圈中使用展开技术,减少迭代的次数,就可以提高效能。上面的叙述相信很多人看到都会有所共鸣,没错!这就是传说中的厨具,阿不是,是传说中的达夫装置(关于达夫装置的定义可以看wiki),简单来说达夫装置是一个迴圈体展开技术,使得一次迭代实际执行了多次迭代的操作,最初是用在 C 语言中,后面则出现 JavaScript的应用版本,其 code 如下:

var iterations = Math.floor(items.length/8),      startAt = items.length%8,      i = 0;  do{      switch(startAt){          case 0 : process(items[i++]);          case 7 : process(items[i++]);          case 6 : process(items[i++]);          case 5 : process(items[i++]);          case 4 : process(items[i++]);          case 3 : process(items[i++]);          case 2 : process(items[i++]);          case 1 : process(items[i++]);      }      startAt =  0;   }while(--iterations);

但根据网路神人实测,当迭代量少时,使用达夫装置反而会适得其反,所以使用上还需自行评估喔>Q^

六. 迴圈中的边缘人- while

判断式有其边缘人 switch,迴圈当然也有!就是 while-loop~~
while-loop 使用上与 for-loop 用途一样,用来重覆执行 while(for) 区块内的语句,但是,就是这个但是,使用 while-loop 时,如果一不小心忘记给他一个计算值,使其有办法跳出迴圈,就很容易产生可怕的无限循环~再加上使用上的美观程度跟效能也不会比 for 迴圈来得高,所以活该被遗忘较少人使用。
但是其实 while 迴圈有一个鲜为人知的用法,就是 do...while 迴圈,它的语法如下:

do {  //欲进行的动作} while (判断目标);

这个方法与一般的 while-loop 类似,比较特别的是他会先执行一次动作才开始判断,当遇到需要先执行后判断的状况时,就可以活用 do...while 迴圈达到目的,并且能让 while-loop 增加就业机会~真滴佛心!

以上就是本篇彙整个几个优化小撇步,之后如果有遇到或学到更多撇步再来补充啰~上述内容如果有任何问题烦请告知,小弟会立即修正!!!也希望如果有其他优化的小技巧,大家能不吝分享~~让世界更美好,也能救救可怜的初学者(跪)!


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章