也許可以不用 If… Else

繆宇發表於2018-06-21

之前在寫一個 React 專案時,我發現我用了太多的 if else,於是在重構程式碼的時候,我嘗試刪除了大量的 if else,最終發現程式碼變簡潔了,可讀性更高了。所以如果你的程式碼中也出現了大量的if else,說明你的程式碼出問題了。

在 code reviews 的時候,我會關注下面幾個問題:

  • 一個函式幹了幾件事情,是否需要分離,讓一個函式只幹一件事?
  • 檢查函式中的 if else,看是否可以替換它。
  • 怎麼改善可讀性?比如用設計模式替換if else(我最喜歡用物件對映模式)。
  • 如果必須使用 if else,那麼刪除 else,保留 if,並返回預設值。

接下來我會舉幾個例子來展示如何替代 if else

刪除 else

重構前:

if (red) {
  return false;
} else if (blue) {
  return false;
} else {
  return true;
} 
複製程式碼

重構後:

if (red || blue) {
    return false;
}
return true;
複製程式碼

重構後的程式碼可以很直觀的看到預設返回值,更簡潔易讀。

組合函式

當你發現一個函式做了很多件事情,那麼用組合函式可以很好的處理它。把函式分離成多個函式,然後把它們組合起來。

舉個例子:我們來建立一個可以生成包含皮毛和爪子的雌性動物的函式

import { flow } from 'lodash';

const femaleAnimalsWithFurAndClaws = flow(
  getFemales,
  getAnimalsWithFur,
  getAnimalsWithClaws,
)(animals);
複製程式碼

程式碼處理成這樣,我們可以很輕鬆的重用裡面的函式(比如 getFemales)。

物件對映模式

這是我最喜歡的設計模式之一,可使用的場景也很多,不管是在前端還是後端編碼中都可以用。它帶來的好處就是,讓程式碼簡潔易讀。每次我用這種設計模式的時候,我都覺得我的程式碼不是程式碼,而是說明書(^_^)。

來看一個簡單的例子:

const colors = {
  red: false,
  blue: false,
  'default': true,
 };

const colorMapper = color => colors[color] || colors['default'];

const color = colorMapper(item.color);
複製程式碼

它由兩個部分組成,一個儲存返回結果的物件和一個對映函式。

我們設定了預設值,即使在呼叫 colorMapper 函式的時候,沒有傳入引數,或者傳入了錯誤引數,都不會報錯,並返回預設值。後期維護的時候,我們也可以很輕鬆的新增其他的顏色。

當然我們也可以用 switch 來達到同樣的效果,就我個人而言並不喜歡這種語法,還是物件對映的方式更簡潔優美(^_^)。

物件對映模式 + React

用 React 寫專案,才是物件對映模式大放異彩的時候。當我們渲染很多不同的元件時,我們需要在程式碼中寫大量的條件判斷。如果用物件對映模式,問題就變得簡單了。看下面的例子:

首先資料看起來是這樣的,每個物件都有一個 typecontent 鍵。

const items = [{
 type: ‘hero’,
 content: : {…},
}, {
 type: 'text',
 content: : {…},
}, {
 type: 'image_and_text',
 content: : {…},
}, {
 type: 'text',
 content: : {…},
}, {
 type: 'call_to_action',
 content: : {…},
}];
複製程式碼

然後寫一個對映函式,每個鍵表示一個 React 元件,每個元件都有 prop,就上面資料中的 content

const components = {
 hero: HeroComponent,
 text: TextComponent,
 image_and_text: ImageAndTextComponent,
 call_to_action: CallToActionComponent,
 'default': null,
};

const componentMapper = type => 
components[type] || components['default'];
複製程式碼

接下來就可以在專案中用了:

import react from ‘react’;

const RenderItems = props => {
 
 const componentList = props.items((item, index) => {
   const Component = componentMapper(item.type);
   return <Component content={item.content} />
 };

 return (
  <div>
   {componentList}
  </div>
 )
};
複製程式碼

感謝閱讀!

本文翻譯自Fredrik JensenIf… Else, or not!

相關文章