上一篇中,我們主要專注在討論偏向命名、排版等大多數與易讀性直接相關的議題。
這篇中,我則想要分享的更偏向一些讓程式更為簡潔的小技巧。相較於上一篇,今天要講的許多內容就更為主觀,最後的使用權與判斷還是交由你來決定。
首先我們還是先從一個 必須遵守的 Coding Style 開始講,這邊主要是複習之前的 Scope 實作建議。
其實控管 Scope 最重要的一點就是要遵守最小暴露原則。如同物件導向的封裝,我們必須要隱藏外部不需知道的細節。封裝有幾個好處:
良好的封裝可以 大大的增加 可維護性,而封裝這個概念在每個函式中都是可以實踐的,只要把外部用不到的變數放在內部函式中即可
假設我們今天有一個變數 onlyForMyFn 只有在 myFn 才會使用到,例如:
var onlyForMyFn = 'only for inner function';
function myFn() {
    // do something to 'onlyForMyFn'
}
// other codes ...
那應該要改成這樣更為適當:
function myFn() {
    var onlyForMyFn = 'only for inner function';
    // do something to 'onlyForMyFn'
}
// other codes ...
如此外部就無法動用到 onlyForMyFn 這個變數,這樣可以有效減少 myFn 執行錯誤的機率。
在 JavaScript 中,一個很好的封裝方法就是利用 IIFE 包裹你的檔案,並只回傳要公開的 API 就好。如下:
var myLibrary = (function() {
  var interface = {
        api1: api1,
        api2: api2,
    	...
      };
  function api1(name) {
	  // ...
  }
  function api2(name) {
	  // ...
  }
  // more codes ...
  return interface;
})();
可以看到,藉由這種模組化的做法,我們將整個要公開的 API 都濃縮在一個物件裡,因此我們只會在全域多新增一個物件而已。比起不用 IIFE 包裹,並且讓 API 散落在全域中,模組化會是一個好很多的選擇。
我認為簡潔程式與易讀性有很大的關連。當我們可以把程式縮減的比較短,同時也能保持程式一目了然的話,讀起來不是會更舒服嗎?
什麼是匿名 callback 強迫症呢?讓我們看看範例:
壞例子:
setTimeout(function() {
	wakeUp();
}, 100);
function wakeUp() {
  console.log('time to wakeup');
}
有沒有發現哪邊怪怪的呢?既然我們在匿名函式中只有要執行 wakeUp,那為什麼不乾脆傳入 wakeUp 就好了呢?
好例子:
setTimeout(wakeUp, 100);
function wakeUp() {
  console.log('time to wakeup');
}
這樣我們可以很快地減少兩行完全不必要且不利於閱讀的程式碼。現在,整個程式頓時清爽了許多。
拒絕匿名 callback 強迫症是你我都該做的事情。
這點曾在 原始型別篇 提過。如果今天我們要判斷一個值是否為 undefined 或是 '',依照其他語言的習慣我們可以這樣寫:
不使用 Truthy & Falsy
if ((value === undefined) && (value === '')) {
	// do something
}
那不如就簡化成:
使用 Truthy & Falsy ( 較建議 )
if (!value) {
	// do something
}
會簡潔許多
又或者說要回傳一個 boolean 值
不使用 Truthy & Falsy
function returnBoolean() {
  	// ..
	return Boolean(value1) && Boolean(value2);
}
那不如這樣簡化
使用 Truthy & Falsy ( 較建議 )
function returnBoolean() {
  	// ..
	return !!value1 && !!value2;
}
利用 Truthy & Falsy 可以有效提高易讀性。
善用三元運算式 可以讓程式更為簡潔。
假設現在我們要決定圖片的高度與寬度,如果大於 200 就設為兩百:
使用 if:
function myFn(height, width) {
  if (height > 200) {
    height = 200;
  }
  if (width > 200) {
    width = 200;
  }
  // do something
}
這會是一般的寫法,如果使用三元運算式的話,我們可以將程式簡化成這樣:
使用 三元運算式 ( 較推薦 )
function myFn(height, width) {
  height = (height > 200) ? 200 : height;
  width = (width > 200) ? 200 : width;
  // do something
}
使用三元運算式可以讓程式更為簡潔,除此之外,閱讀者也可以很清楚的知道你的意圖就是要賦值 ( 因為開頭就是 變數 = ...  )。
更進一步,我們還可以把 三元運算式 運用在決定函式上。
舉個例子來說,假設我們今天依照想不想睡來決定要做什麼事情,我們可能會這樣寫
使用 if:
function doSomething(isSleepy) {
  if (isSleepy) {
    drinkCoffee();
  } else {
    startCoding();
  }
}
function drinkCoffee() {...} 
function startCoding() {...} 
如果使用三元運算式的話:
使用 三元運算式
function doSomething(isSleepy) {
  var decision = isSleepy ? drinkCoffee : startCoding;
  decision();
}
function drinkCoffee() {...} 
function startCoding() {...} 
這樣也不失為一種做法。當然,相較於使用三元運算式還單純賦值,使用三元運算式來決定要使用哪個函式可能就更為主觀了!
與善用三元運算式一樣,Operator 會是簡潔程式碼強大的工具。
讓我們把剛剛圖片寬高的需求稍作修改,假設我們的寬與高是 undefined 的話,就把他們設為 200,否則保持原值。
不使用 Operator:
function myFn(height, width) {
  if (!height) {
    height = 200;
  }
  if (!width) {
    width = 200;
  }
  // do something
}
使用 Operator ( 較建議 ):
function myFn(input) {
  height = height || 200;
  width = width || 200;
  // do something
}
可以看到,在這個範例中,相較於第一個作法,使用 || Operator 會更壓倒性的易讀。
在 JavaScript 中還有許多的 Operator,在這邊就不再贅述,但我們要知道如果對於各種 Operator 都有更深的了解,也許就會發現新的一片天。
if return vs if {}同樣是另一個主觀的意見,如果我們的 if 是要拿來做一些是否要接續執行函式的判斷,那麼可以用 if return 來取代 if {}。
這句話是什麼意思呢?首先讓我們來看看範例,現在我們要檢查 input 是否為 undefined,如果不是 undefined 的話我們才要接著做事。很直覺的作法會如下:
使用 if {}
function myFn(input) {
	if (input) {
      // do something
	}
}
相較於這種風格,我會更喜歡以下這種寫法:
使用 if return ( 較推薦 )
function myFn(input) {
	if (!input) return;
    // do something
}
這種寫法中言簡意賅的表示,如果 input 是 undefined 等 falsy 值,就可以直接略過這個函式不看了。
相較之下,使用第一個寫法的話,在 trace 程式碼時你還要確定 if 結束的 } 位置是不是真的在函式的最下方,畢竟有可能在 } 之後還有做其他的事。
還有另外一點是,if return 可以讓程式的排版變得更扁平化。舉例來說,假如今天這個函式包含了很多其他的邏輯,那你的函式可能就會有變成 波動拳 的趨勢了:
使用 if {}
function myFn(input) {
	if (input) {
        if (...) {
            // do something
        }
	}
}
那讓我們採用 return 寫法來看看:
使用 if return ( 較推薦 )
function myFn(input) {
	if (!input) return;
    if (...) {
        // do something
    }
}
這樣是不是清爽很多呢?
這篇中介紹了一些偏向小技巧的 Coding Style。
有注意到嗎,其實 Coding Style 就像是對於程式的執著與熱誠,只要在小細節多思考、多留心,就能夠做出巨大的改變,不但能寫出優雅許多的程式,我們也會因為這些執著與經驗的累積而變成更好的程式設計師。
工作上的小經驗 與 前輩們的指導