對於代碼裡面的 if else,我們可以使用邏輯判斷式,或更好的三元判斷式來優化代碼。除了可以降低維護項目的成本之外,還可以提升代碼可讀性。就讓我們從最簡單的 if else 例子開始吧。
最簡單的 if...else...
或者 switch
都是 JavaScript 的入門,我們這裡就簡單說一下:
if (workIsDone === true) {
eatDinner();
} else {
keepCoding();
}
表達式與陳述句
首先我們要了解什麼是表達式(Expressions),什麼是陳述句(Statements)。
表達式是任何句子用來給 JavaScript 引擎展開,並產生值。
例如,它可以是一個數字,數組,對象,正則表達式,賦值,函數。
陳述句這是任何句子用來給 JavaScript 引擎讓某些事物發生,或者由副作用。
例如:條件命令式,變量,循環,返回,try/catch/finally
。
條件和真假值
何為真?何為假?萬物有所變,但 JavaScript 引擎卻有所定義。
假
我們可以簡單地用 A == false
來判斷假的值。
'' 或 "" 或 ``
0 或 -0
null
undefined
NaN
false
值得注意的是,使用模板字符串而裡面沒有填充任何值的話,也是會返回 false
的。
真
非假為真
如何優雅地寫出條件判斷式
還記得 De Morgan's Laws
嗎?
我們可以用它來簡化複雜的條件判斷式:
!(A || B) === (!A && !B); // true
!(A && B) === (!A || !B); // true
實戰部分
對於 Google Analytics(GA),我們不希望把作者本人的數據,以及測試環境的數據也上傳上去,以免干擾資料正確性。我們就可以問用戶是否已經作者本人,以及是否在測試環境上,來判斷是否需要寄送 Google Analytics 數據到 Google 服務器上。
假設兩個函數已經寫好了,比如說 isAuthor()
和 isTestingEnvironment()
。
只有在不是作者本人,或者
當前環境不是測試環境,我們才寄送數據到 Google 服務器上。
const enableGA = !(isAuthor() || isTestingEnvironment());
const betterEnableGA = !isAuthor() && !isTestingEnvironment();
當然,更加好的寫法是只有當用戶不是作者本人,以及
不在測試環境上,我們才寄送數據到 Google 服務器上。
const enableGA = isNotAuthor() && isNotTestingEnvironment();
優化 if else 的不同手段
以 && 取代單純的 if 語句
if (user && user.canDeletePost) {
deletePost();
}
以上的代碼可以取代為:
user && user.canDeletePost && deletePost();
當然,如果你認為這樣寫的代碼太長,會有副作用,那麼你可以簡化為:
const userCanDeletePost = user && user.canDeletePost;
userCanDeletePost && deletePost();
以 || 取代 if else 語句
我們這裡會用一個判斷用戶密碼長度的簡單函數作為例子。如果你有更加好的代碼片段,歡迎在底部的評論區留言。
let strength = null;
if (password.length > 7) {
strength = "Strong";
} else {
strength = "Weak";
}
以上的代碼可以取代為:
const strength = (password.length > 7 && "Strong") || "Weak";
然而,使用 &&
加 ||
的組合會增加程序員閱讀代碼的思維層數,一種更加好的做法是使用三元運算符(ternary operator)。
值得注意的是,如果你的 &&
之後 的 A 是一個 falsy 的值,它永遠不會返回,而是返回 B。
(condition && A) || B;
// 例如:
let password = "abcdefg1234";
(password.length > 7 && false) || "Weak"; // 'Weak'
password = "a";
(password.length > 7 && false) || "Weak"; // 'Weak'
我們可以使用三元運算符而不是邏輯運算符來更好地表達語句。
三元運算符
最簡單的三元運算符會是,條件為真?返回 A,不然返回 B。
condition ? A : B;
針對以上的例子,判斷密碼長度的代碼片段可以改為:
const strength = password.length > 7 ? "Strong" : "Weak";
另外一個例子,就是在支持多瀏覽器的 AJAX 庫裡面可以得出的代碼片段:
let xmlhttp = null;
if (window.XMLHttpRequest) {
// 現代瀏覽器
xmlhttp = new XMLHttpRequest();
} else if (window.ActiveXObject) {
// 舊 IE 版本 (IE <= 6)
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
我們可以使用邏輯運算符來優化以上代碼片段:
const xmlhttp =
(window.XMLHttpRequest && new XMLHttpRequest()) ||
(window.ActiveXObject && new ActiveXObject("Microsoft.XMLHTTP")) ||
null;
或使用更加好的三元運算符來優化以上代碼片段:
const xmlhttp = window.XMLHttpRequest
? new XMLHttpRequest()
: window.ActiveXObject
? new ActiveXObject("Microsoft.XMLHTTP")
: null;
值得注意的是,三元判斷式是從右到左結合的:
// 這個判斷式
A
? B
: C
? D
: E
? F
: G(
// 等同以下判斷式
A ? B : C ? D : E ? F : G
); // B
然而,你可能是想寫:
((A ? B : C) ? D : E) ? F : G; // F
所以,記得自己加括號來控制代碼如何結合解析。
後記
上個星期,組織舉辦了一場前端 Code Review 的大會,其中優化 if...else...
的手法,讓我有所體悟。之後,我花了點時間研究邏輯判斷式及三元判斷式。希望能夠達到知其然,知其所以然的階段。
對於第一段代碼,我們可以簡化為以下代碼:
workIsDone ? eatDinner() : keepCoding();
順帶一提,不知道為什麼這一篇文章的底部評論區有問題,請移玉步到右上角的留言簿。