重構 - 程式碼優化技巧

飢人谷前端發表於2018-01-24

本文為飢人谷講師方方原創文章,首發於 前端學習指南

以下是我《JS深入淺出》第6課的講義,如果對你有幫助點個贊即可

這次課講的是「如何提高程式碼的可讀性」,跟前端關係不大,是寫程式碼的普遍技巧。

注意我們講得不是「如何提高程式碼的效能」。

程式碼優化基本原則

  1. 易讀性優先
  2. 如果不是效能瓶頸,就不要為了效能而改寫程式碼
  3. 複雜性守恆原則:無論你怎麼寫程式碼,複雜性都是不會消失的 推論:如果邏輯很複雜,那麼程式碼看起來就應該是複雜的。如果邏輯很簡單,程式碼看起來就應該是簡單的。

命名

程式設計師三大難題

  1. 變數命名
  2. 快取失效
  3. 迴圈邊界 可見變數命名的重要性。

網上有很多命名規範,大家可以參考。本節課只講基本原則。

一、注意詞性

  • 普通變數/屬性用「名詞」
var person = {
      name: 'Frank'
  }
  var student = {
      grade: 3,
      class: 2
  }
複製程式碼
  • bool變數/屬性用「形容詞」或者「be動詞」或者「情態動詞」或者「hasX」
var person = {
      dead: false, // 如果是形容詞,前面就沒必要加 is,比如isDead 就很廢話
      canSpeak: true, //情態動詞有 can、should、will、need 等,情態動詞後面接
動詞
      isVip: true, // be 動詞有 is、was 等,後面一般接名詞
      hasChildren: true, // has 加名詞
  }
複製程式碼
  • 普通函式/方法用「動詞」開頭
var person = {
      run(){}, // 不及物動詞
      drinkWater(){}, // 及物動詞
      eat(foo){}, // 及物動詞加引數(引數是名詞)
  }
複製程式碼
  • 回撥、鉤子函式用「介詞」開頭,或用「動詞的現在完成時態」
var person = {
      beforeDie(){},
      afterDie(){},
      // 或者
      willDie(){}
      dead(){} // 這裡跟 bool 衝突,你只要不同時暴露 bool dead 和函式 dead 就行,怕衝突就用上面的 afterDie
  }
  button.addEventListener('click', onButtonClick)
  var component = {
      beforeCreate(){},
      created(){},
      beforeMount(){},
      mounted(){},
      beforeUpdate(){},
      updated(){},
      activated(){},
      deactivated(){},
      beforeDestroy(){},
      destroyed(){},
      errorCaptured(){}
  }
複製程式碼
  • 容易混淆的地方加字首
div1.classList.add('active') // DOM 物件
  div2.addClass('active') // jQuery 物件
  不如改成
  domDiv1 或 elDiv1.classList.add('active')
  $div2.addClass('active')
複製程式碼

屬性訪問器函式可以用名詞

$div.text() // 其實是 $div.getText()
  $div.text('hi') // 其實是 $div.setText('hi')
複製程式碼

二、注意一致性

  • 介詞一致性 如果你使用了 before + after,那麼就在程式碼的所有地方都堅持使用 如果你使用了 before + 完成時,那麼就堅持使用 如果你改來改去,就「不一致」了,不一致將導致「不可預測」
  • 順序一致性 比如 updateContainerWidth 和 updateHeightOfContainer 的順序就令人很彆扭,同樣會引發「不可預測」
  • 表裡一致性 函式名必須完美體現函式的功能,既不能多也不能少。 比如
function getSongs(){
      return $.get('/songs).then((response){
          div.innerText = response.songs
      })
  }
複製程式碼

就違背了表裡一致性,getSongs 表示獲取歌曲,並沒有暗示這個函式會更新頁面,但是實際上函式更新了 div,這就是表裡不一,正確的寫法是

  • 要麼糾正函式名
function getSongsAndUpdateDiv(){
      return $.get('/songs).then((response){
          div.innerText = response.songs
      })
  }
複製程式碼
  • 要麼寫成兩個函式
function getSongs(){
      return $.get('/songs)
  }
  function updateDiv(songs){
      div.innerText = response.songs
  }
  getSongs().then((response)=>{
      updateDiv(response.songs)
  })
複製程式碼
  • 時間一致性 有可能隨著程式碼的變遷,一個變數的含義已經不同於它一開始的含義了,這個時候你需要及時改掉這個變數的名字。 這一條是最難做到的,因為寫程式碼容易,改程式碼難。如果這個程式碼組織得不好,很可能會出現牽一髮而動全身的情況(如全域性變數就很難改)

改程式碼

如果你的程式碼有單元測試,那麼改起來就很放心。如果沒有單元測試,就需要用「小步快跑」的策略來修改。

小步快跑的意思是說,每次只修改一點點,測試通過後,再修改一點點,再測試,再修改一點點……如此反覆。

那麼如何修改一點點呢?《重構》這本書介紹了很多方法,但是講得有點抽象的,如果你有時間可以看看。

我這裡只說兩個經久不衰的方法。

一、使用函式來改程式碼

步驟:

  1. 將一坨程式碼放到一個函式裡
  2. 將程式碼依賴的外部變數作為引數
  3. 將程式碼的輸出作為函式的返回值
  4. 給函式取一個合適的名字
  5. 呼叫這個函式並傳入引數
  6. 這個函式裡的程式碼如果超過 5 行,則依然有優化的空間,請回到第 1 步

二、使用物件來改程式碼

如果使用了函式改造法改造後,發現有太多的小函式,則可以使用物件將這些函式串起來。

記得我們講過「this 是函式和物件的橋樑」嗎,我們會用 this 來串聯這個物件和所有函式。

最終程式碼:http://js.jirengu.com/mimazaboke/1/edit?html,js,output

一些固定的套路

  1. 表驅動程式設計(《程式碼大全》裡說的) 所有一一對應的關係都可以用表來做
  2. 自說明程式碼(以 API 引數為例) 把別人關心的東西放在顯眼的位置

bad smell(壞味道)

有些程式碼可以用,但是很「臭」。

哪些程式碼是有壞味道的

  1. 表裡不一的程式碼
  2. 過時的註釋
  3. 邏輯很簡單,但是看起來很複雜的程式碼
  4. 重複的程式碼
  5. 相似的程式碼
  6. 總是一起出現的程式碼

破窗效應

此理論認為環境中的不良現象如果被放任存在,會誘使人們仿效,甚至變本加厲。一幢有少許破窗的建築為例,如果那些窗不被修理好,可能將會有破壞者破壞更多的窗戶。最終他們甚至會闖入建築內,如果發現無人居住,也許就在那裡定居或者縱火。一面牆,如果出現一些塗鴉沒有被清洗掉,很快的,牆上就佈滿了亂七八糟、不堪入目的東西;一條人行道有些許紙屑,不久後就會有更多垃圾,最終人們會視若理所當然地將垃圾順手丟棄在地上。這個現象,就是犯罪心理學中的破窗效應。

程式設計師要做到:只要是經過你手的程式碼,都會比之前好一點。

加微訊號: astak10或者長按識別下方二維碼進入前端技術交流群 ,暗號:寫程式碼啦

每日一題,每週資源推薦,精彩部落格推薦,工作、筆試、面試經驗交流解答,免費直播課,群友輕分享... ,數不盡的福利免費送

重構 - 程式碼優化技巧

相關文章