<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          讓你的 JS 代碼變得干凈優(yōu)雅且可維護

          共 8221字,需瀏覽 17分鐘

           ·

          2021-08-20 10:27

          點擊上方 程序員成長指北,關(guān)注公眾號

          回復1,加入高級Node交流群

          拒絕魔法

          眾所周知,魔法是這樣的:

          哦,不是。。

          在編程的世界里也有魔法,一般稱其為:魔法數(shù)字,魔法變量,魔法字符串。例如這樣:

          const a = await abcdefg();
          console.log(a === 200);
          const b = await asdfgh();
          if (b === 0) {
          else if (b === 1) {
          else if (b === 2) {};
          for (let i = 0; i < 10; i++) {};

          以上直接出現(xiàn)的,莫名其妙的變量名,字符串以及判斷條件數(shù)字,就叫魔法。。。

          這種寫法寫出來的代碼晦澀難懂,難以維護,隱藏 BUG 多,除非你準備給接手的人埋坑,或者準備辭職,不然千萬別這么寫(容易被打斷腿,????? )

          那么怎么寫才更優(yōu)雅?

          語義化

          首先便是語義化。一個是變量,常量的語義化,例如:

          const SUCCESS_STATUS = 200;
          const requestStatus = await getStatus();
          console.log(requestStatus === SUCCESS_STATUS);
          const userRole = await getUserRole();
          const GUEST_CODE = 0;
          const USER_CODE = 1;
          const ADMIN_CODE = 2;
          if (userRole === GUEST_CODE) {
          else if (userRole === USER_CODE) {
          else if (userRole === ADMIN_CODE) {};
          const MAX_NUM = 10;
          const MIN_NUM = 0;
          for (let currentNum = MIN_NUM; currentNum < MAX_NUM; currentNum++) {};

          一般的規(guī)則就是變量用小寫,常量用大寫,把變量名語義化,那么當你看到這段代碼的時候,一眼就能知道它是做什么的,而不是非得要浪費時間看完上下文,或者是猜。

          枚舉

          對于上面判斷 userRole 的代碼,其實我們可以用更優(yōu)雅的方式去實現(xiàn),那就是 枚舉 。

          按照維基百科的說明:在數(shù)學和計算機科學理論中,一個集的枚舉是列出某些有窮序列集的所有成員的程序,或者是一種特定類型對象的計數(shù)。這兩種類型經(jīng)常(但不總是)重疊。

          其實就是組織收集有關(guān)聯(lián)變量的一種方式。枚舉的好處在于方便多狀態(tài)的管理,以及可讀性更強。例如:

          const ROLES = {
            GUEST0,
            USER1,
            ADMIN2
          };
          const userRole = await getUserRole();
          if (userRole === ROLES.GUEST) {
          else if (userRole === ROLES.USER) {
          else if (userRole === ROLES.ADMIN) {};

          通過枚舉的方式歸納起來,維護起來更方便,而且要添加狀態(tài)直接在 ROLES 對象里寫就行,更方便快捷。

          策略模式

          維基百科上說:策略模式作為一種軟件設(shè)計模式,指對象有某個行為,但是在不同的場景中,該行為有不同的實現(xiàn)算法。

          上面的代碼依舊是可優(yōu)化的,在這里我們可以利用策略模式來做進一層的優(yōu)化。

          具體的例子就是如下:

          const ROLES = {
            GUEST0,
            USER1,
            ADMIN2
          };
          const ROLE_METHODS = {
            [ROLES.GUEST]() {},
            [ROLES.USER]() {},
            [ROLES.ADMIN]() {},
          };
          const userRole = await getUserRole();
          ROLE_METHODS[userRole]();

          通過上面的寫法,我們可以知道,當我們需要增加角色,或者修改角色數(shù)字的時候,只需要修改 ROLES 里對應(yīng)的字段,以及 ROLE_METHODS 里的方法即可,這樣我們就可以將可能很冗長的 if...else 代碼給抽離出來,顆粒度更細,更好維護。

          更在狀態(tài)

          除了上面的方式之外,我們還可以利用“ 狀態(tài) ”的概念來寫代碼。在看代碼之前,我們先了解下什么是 “有限狀態(tài)機”。

          根據(jù)維基百科的解釋:有限狀態(tài)機(英語:finite-state machine,縮寫:FSM)又稱有限狀態(tài)自動機(英語:finite-state automation,縮寫:FSA),簡稱狀態(tài)機,是表示有限個狀態(tài)以及在這些狀態(tài)之間的轉(zhuǎn)移和動作等行為的數(shù)學計算模型。

          例如我們熟悉的 Promise ,它就是在狀態(tài)集:PENDIN 、 FULFILLED 、 REJECTED  之間單向流轉(zhuǎn)的有限狀態(tài)機。

          狀態(tài)機的概念跟策略模式類似,實現(xiàn)方式也類似,這里面最大的不同是在于 “語義” 。

          策略模式更適合于互不依賴,同時只能存在一個狀態(tài)的場景,例如:

          const 吃 = {
            沙縣大酒店() {
              吃云吞()
            },
            開封菜() {
              吃漢堡()
            },
            在家() {
              吃外賣()
            }
          };

          這里面如果我們肚子餓了,就只能在 沙縣大酒店() , 開封菜() , 在家() 這幾個狀態(tài)里選。

          你不能都吃,當然以下情況除外。。。

          如果是狀態(tài)模式,則會有這種情況:

          const 打工人 = {
            起床() {},
            上班() {},
            加班() {},
            下班() {}
          };
          // 早上6點
          打工人.起床();
          // 早上9點
          打工人.上班();
          // 晚上6點
          打工人.加班();
          // 晚上12點
          打工人.下班();

          這里的打工人根據(jù)不同的時間,進行不同的任務(wù),便是打工人模式,哦不,狀態(tài)模式。這里的時間就是狀態(tài)。

          我們舉個實際的業(yè)務(wù)例子,就是訂單列表頁,通常我們的訂單可能有這幾種狀態(tài):

          不同的狀態(tài)展示的 UI 也不同,所以我們以不同的狀態(tài)劃分好模塊之后,代碼寫起來就會清晰很多,我們以 Vue 代碼為例:

          // contants.js
          export const ORDER_STATUS = {
            INIT0// 初始化
            CREATED1// 訂單創(chuàng)建
            ARREARAGE2// 待支付
            PURCHASED3// 已購買
            SHIPPED4// 已發(fā)貨
            COMPLETED5 // 已完成
          };
          // order.vue
          <template>
          <div>
          <section v-if="orderIsInit"></section>
          <section v-if="orderIsCreated"></section>
          <section v-if="orderIsArrearage"></section>
          <section v-if="orderIsPurchased"></section>
          <section v-if="orderIsShipped"></section>
          <section v-if="orderIsCompleted"></section>
          </div>
          </template>

          <script>
          import ORDER_STATUS from './contants';
          import eq from 'lodash';

          export default {
          computed: {
          /**
          * @func
          * @name orderIsInit
          * @desc 判斷訂單是否初始化的狀態(tài)
          * @returns {string} 判斷訂單是否初始化的狀態(tài)
          */
          orderIsInit() {
          return eq(this.orderStatus, ORDER_STATUS.INIT);
          },
          /**
          * @func
          * @name orderIsCreated
          * @desc 判斷訂單是否已創(chuàng)建的狀態(tài)
          * @returns {string} 訂單是否已創(chuàng)建
          */
          orderIsCreated() {
          return eq(this.orderStatus, ORDER_STATUS.CREATED);
          },
          /**
          * @func
          * @name orderIsArrearage
          * @desc 判斷訂單是否未付款的狀態(tài)
          * @returns {string} 訂單是否未付款
          */
          orderIsArrearage() {
          return eq(this.orderStatus, ORDER_STATUS.ARREARAGE);
          },
          /**
          * @func
          * @name orderIsPurchased
          * @desc 判斷訂單是否已購買的狀態(tài)
          * @returns {string} 訂單是否已購買
          */
          orderIsPurchased() {
          return eq(this.orderStatus, ORDER_STATUS.PURCHASED);
          },
          /**
          * @func
          * @name orderIsShipped
          * @desc 判斷訂單是否已發(fā)貨的狀態(tài)
          * @returns {string} 訂單是否已發(fā)貨
          */
          orderIsShipped() {
          return eq(this.orderStatus, ORDER_STATUS.SHIPPED);
          },
          /**
          * @func
          * @name orderIsCompleted
          * @desc 判斷訂單是否已完成的狀態(tài)
          * @returns {string} 訂單是否已完成
          */
          orderIsCompleted() {
          return eq(this.orderStatus, ORDER_STATUS.COMPLETED);
          },
          },
          data() {
          return {
          orderStatus: ORDER_STATUS.INIT // 訂單狀態(tài)
          }
          },
          methods: {
          /**
          * @func
          * @name getOrderStatus
          * @desc 判斷訂單狀態(tài)
          * @returns {string} 返回當前訂單狀態(tài)
          */
          async getOrderStatus() {}
          },
          async created() {
          this.orderStatus = await this.getOrderStatus();
          }
          }
          </script>

          將頁面組件按狀態(tài)劃分,實現(xiàn)獨立自治,這樣子既能防止代碼耦合,方便維護 debug,也方便開發(fā)者自測,如果需要看不同狀態(tài)的展示效果,只要手動給 orderStatus 賦值即可,方便快捷。

          面向切面

          按照維基百科的解釋:面向切面的程序設(shè)計(Aspect-oriented programming,AOP,又譯作面向方面的程序設(shè)計、剖面導向程序設(shè)計)是計算機科學中的一種程序設(shè)計思想,旨在將橫切關(guān)注點與業(yè)務(wù)主體進行進一步分離,以提高程序代碼的模塊化程度。

          上面這段文字估計沒有什么人看,算了,直接上代碼吧

          我們看回上面打工人的場景,假定老板想要知道打工人每個狀態(tài)開始前跟結(jié)束前的時間以及做點什么,那么該怎么做呢?這個時候我們不難想到可以直接往狀態(tài)函數(shù)里寫代碼,例如:

          const 打工人 = {
            起床() {
              老板.start();
              打工人.do();
              老板.end();
            },
            上班() {
              老板.start();
              打工人.do();
              老板.end();
            },
            加班() {
              老板.start();
              打工人.do();
              老板.end();
            },
            下班() {
              老板.start();
              打工人.do();
              老板.end();
            }
          };
          // 早上6點
          打工人.起床();
          // 早上9點
          打工人.上班();
          // 晚上6點
          打工人.加班();
          // 晚上12點
          打工人.下班();

          但是這樣打工人一下子就察覺到到了老板在監(jiān)控他的生活,如果要做到不被人察覺(不影響業(yè)務(wù)邏輯),那我們既可以采用 AOP 的實現(xiàn)方式。代碼如下:

          import eq from 'lodash';
          const TYPES = {
            FUNCTION'function'
          }
          const 老板監(jiān)控中的打工人 = new Proxy(打工人, {
              get(target, key, value, receiver) {
                  console.log('老板開始看你了~');
                 const res = Reflect.get(target, key, value, receiver);
                 const 打工人任務(wù) = eq(typeof res, TYPES.FUNCTION) ? res() : res;
                  console.log('老板開始記你小本本了~');
                  return () => 打工人任務(wù);
              }
          });

          所以我們可以看到以下結(jié)果:

          這樣子,我們就可以輕松簡單地監(jiān)控到了打工人每天干的活,而且還不讓打工人發(fā)現(xiàn),簡直是資本家聽了都流淚呀。

          Node 社群


          我組建了一個氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對Node.js學習感興趣的話(后續(xù)有計劃也可以),我們可以一起進行Node.js相關(guān)的交流、學習、共建。下方加 考拉 好友回復「Node」即可。


             “分享、點贊在看” 支持一波 

          瀏覽 80
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产又色又爽无遮挡免费 | 人妻13p| 亚洲天堂无码视频 | 最新欧美va在线观看 | 国内成人自拍视频 |