「我要努力向上,不付诸君期望」 ~整人专家-胡真~
就前端初学者的思维,大多会把「写出可以运行的 code 」当作是练习或是实作的终极目标,而美化 code 内容或是使其运行效率更快什么的,等到实力累积到一定程度之后在来处理就好。(好吧也有可能只有我是这样想)
但其实世界是美好的~有些优化的关键其实只是透过一些基础概念的运用便可达成,不需要多艰深的知识就能使用自如,本篇就以 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 增加就业机会~真滴佛心!
以上就是本篇彙整个几个优化小撇步,之后如果有遇到或学到更多撇步再来补充啰~上述内容如果有任何问题烦请告知,小弟会立即修正!!!也希望如果有其他优化的小技巧,大家能不吝分享~~让世界更美好,也能救救可怜的初学者(跪)!