前端團隊程式碼評審 CheckList 清單

我是你的超級英雄發表於2019-07-03

前言

前端團隊有評審程式碼的要求,但由於每個開發人員的水平不同,技術關注點不同,所以對程式碼評審的關注點不同,為了保證程式碼質量,團隊程式碼風格統一,特此擬定一份《前端團隊程式碼評審 CheckList 清單》,這樣程式碼評審人員在評審程式碼時,可以參照這份清單,對程式碼進行評審。從而輔助整個團隊提高程式碼質量、統一程式碼規範。如果你的團隊還沒有這麼一份程式碼評審 CheckList 清單,也許這正是你需要的;如果你的團隊已經有了程式碼評審參照標準,這份清單也許能起到錦上添花的效果。

辛苦整理良久,還望手動點贊鼓勵~

github地址為:github.com/fengshi123/…,如果喜歡或者有所啟發,請幫忙給個 star ~,對作者也是一種鼓勵。

一、程式碼靜態檢查工具

1.1、使用 eslint 工具對 javascript 程式碼進行檢查

eslint 檢查的規範繼承自 eslint-config-standard 檢驗規則,具體的規則介紹參照連結:cn.eslint.org/docs/rules/ ,這裡及以下部分不再重複介紹這些檢驗規則。

1.2、使用 stylelint 工具對 css 樣式程式碼進行檢查

stylelint 檢查的規範繼承自 stylelint-config-standard 檢驗規則,具體的規則介紹參照連結:www.npmjs.com/package/sty… ,這裡及以下部分不再重複介紹這些檢驗規則。

二、命名規範

2.1、JS 採用 Camel Case 小駝峰式命名

推薦:

studentInfot複製程式碼

2.2、避免名稱冗餘

推薦:

const Car = {
  make: "Honda",
  model: "Accord",
  color: "Blue"
};複製程式碼

不推薦:

const Car = {
  carMake: "Honda",
  carModel: "Accord",
  carColor: "Blue"
};複製程式碼

2.3、CSS 類名採用 BEM 命名規範

推薦:

.block__element{} 
.block--modifier{}複製程式碼

2.4、命名符合語義化

命名需要符合語義化,如果函式命名,可以採用加上動詞字首:

動詞 含義
can 判斷是否可執行某個動作
has 判斷是否含有某個值
is 判斷是否為某個值
get 獲取某個值
set 設定某個值

推薦:

//是否可閱讀 
function canRead(){ 
   return true; 
} 
//獲取姓名 
function getName{
   return this.name 
} 複製程式碼

三、JS 推薦寫法

3.1、每個常量都需命名

每個常量應該命名,不然看程式碼的人不知道這個常量表示什麼意思。

推薦:

const COL_NUM = 10;
let row = Math.ceil(num/COL_NUM);複製程式碼

不推薦:

let row = Math.ceil(num/10);複製程式碼

3.2、推薦使用字面量

建立物件和陣列推薦使用字面量,因為這不僅是效能最優也有助於節省程式碼量。

推薦:

let obj = {   
     name:'tom',     
     age:15,     
     sex:'男' 
} 複製程式碼

不推薦:

let obj = {};
obj.name = 'tom';
obj.age = 15;
obj.sex = '男';複製程式碼

3.3、物件設定預設屬性的推薦寫法

推薦:

const menuConfig = {
  title: "Order",
  // User did not include 'body' key
  buttonText: "Send",
  cancellable: true
};

function createMenu(config) {
  config = Object.assign(
    {
      title: "Foo",
      body: "Bar",
      buttonText: "Baz",
      cancellable: true
    },
    config
  );

  // config now equals: {title: "Order", body: "Bar", buttonText: "Send", cancellable: true}
  // ...
}

createMenu(menuConfig);
複製程式碼

不推薦:

const menuConfig = {
  title: null,
  body: "Bar",
  buttonText: null,
  cancellable: true
};

function createMenu(config) {
  config.title = config.title || "Foo";
  config.body = config.body || "Bar";
  config.buttonText = config.buttonText || "Baz";
  config.cancellable =
    config.cancellable !== undefined ? config.cancellable : true;
}

createMenu(menuConfig);
複製程式碼

3.4、將物件的屬性值儲存為區域性變數

物件成員巢狀越深,讀取速度也就越慢。所以好的經驗法則是:如果在函式中需要多次讀取一個物件屬性,最佳做法是將該屬性值儲存在區域性變數中,避免多次查詢帶來的效能開銷。

推薦:

let person = {
    info:{
        sex:'男'
    }
}
function  getMaleSex(){
    let sex = person.info.sex;
    if(sex === '男'){
        console.log(sex)
    }
} 複製程式碼

不推薦:

let person = {
    info:{
        sex:'男'
    }
}
function  getMaleSex(){
    if(person.info.sex === '男'){
        console.log(person.info.sex)
    }
} 
複製程式碼

3.5、字串轉為整型

當需要將浮點數轉換成整型時,應該使用Math.floor()或者Math.round(),而不是使用parseInt()將字串轉換成數字。Math 是內部物件,所以Math.floor()其實並沒有多少查詢方法和呼叫時間,速度是最快的。

推薦:

let num = Math.floor('1.6');複製程式碼

不推薦:

let num = parseInt('1.6');複製程式碼

3.6、函式引數

函式引數越少越好,如果引數超過兩個,要使用 ES6的解構語法,不用考慮引數的順序。

推薦:

function createMenu({ title, body, buttonText, cancellable }) {
  // ...
}

createMenu({
  title: 'Foo',
  body: 'Bar',
  buttonText: 'Baz',
  cancellable: true
});
複製程式碼

不推薦:

function createMenu(title, body, buttonText, cancellable) {
  // ...
}
複製程式碼

3.7、使用引數預設值

使用引數預設值 替代 使用條件語句進行賦值。

推薦:

function createMicrobrewery(name = "Hipster Brew Co.") {
  // ...
}
複製程式碼

不推薦:

function createMicrobrewery(name) {
  const breweryName = name || "Hipster Brew Co.";
  // ...
}複製程式碼

3.8、最小函式準則

這是一條在軟體工程領域流傳久遠的規則。嚴格遵守這條規則會讓你的程式碼可讀性更好,也更容易重構。如果違反這個規則,那麼程式碼會很難被測試或者重用 。

3.9、不要寫全域性方法

JavaScript 中,永遠不要汙染全域性,會在生產環境中產生難以預料的 bug。舉個例子,比如你在 Array.prototype 上新增一個 diff 方法來判斷兩個陣列的不同。而你同事也打算做類似的事情,不過他的 diff 方法是用來判斷兩個陣列首位元素的不同。很明顯你們方法會產生衝突,遇到這類問題我們可以用 ES2015/ES6 的語法來對 Array 進行擴充套件。

推薦:

class SuperArray extends Array {
  diff(comparisonArray) {
    const hash = new Set(comparisonArray);
    return this.filter(elem => !hash.has(elem));        
  }
}複製程式碼

不推薦:

Array.prototype.diff = function diff(comparisonArray) {
  const hash = new Set(comparisonArray);
  return this.filter(elem => !hash.has(elem));
};

複製程式碼

 3.10、推薦函數語言程式設計

函式式變程式設計可以讓程式碼的邏輯更清晰更優雅,方便測試。

推薦:

const programmerOutput = [
  {
    name: 'Uncle Bobby',
    linesOfCode: 500
  }, {
    name: 'Suzie Q',
    linesOfCode: 1500
  }, {
    name: 'Jimmy Gosling',
    linesOfCode: 150
  }, {
    name: 'Gracie Hopper',
    linesOfCode: 1000
  }
];
let totalOutput = programmerOutput
  .map(output => output.linesOfCode)
  .reduce((totalLines, lines) => totalLines + lines, 0)
複製程式碼

不推薦:

 const programmerOutput = [
  {
    name: 'Uncle Bobby',
    linesOfCode: 500
  }, {
    name: 'Suzie Q',
    linesOfCode: 1500
  }, {
    name: 'Jimmy Gosling',
    linesOfCode: 150
  }, {
    name: 'Gracie Hopper',
    linesOfCode: 1000
  }
];

let totalOutput = 0;

for (let i = 0; i < programmerOutput.length; i++) {
  totalOutput += programmerOutput[i].linesOfCode;
}複製程式碼

3.11、使用多型替換條件語句

為了讓程式碼更簡潔易讀,如果你的函式中出現了條件判斷,那麼說明你的函式不止幹了一件事情,違反了函式單一原則 ;並且絕大數場景可以使用多型替代

推薦:

class Airplane {
  // ...
}
// 波音777
class Boeing777 extends Airplane {
  // ...
  getCruisingAltitude() {
    return this.getMaxAltitude() - this.getPassengerCount();
  }
}
// 空軍一號
class AirForceOne extends Airplane {
  // ...
  getCruisingAltitude() {
    return this.getMaxAltitude();
  }
}
// 賽納斯飛機
class Cessna extends Airplane {
  // ...
  getCruisingAltitude() {
    return this.getMaxAltitude() - this.getFuelExpenditure();
  }
}
複製程式碼

不推薦:

class Airplane {
  // ...

  // 獲取巡航高度
  getCruisingAltitude() {
    switch (this.type) {
      case '777':
        return this.getMaxAltitude() - this.getPassengerCount();
      case 'Air Force One':
        return this.getMaxAltitude();
      case 'Cessna':
        return this.getMaxAltitude() - this.getFuelExpenditure();
    }
  }
}複製程式碼

3.12、定時器是否清除

程式碼中使用了定時器 setTimeoutsetInterval,需要在不使用時進行清除。

四、SCSS 推薦寫法

4.1、變數 $ 使用

利用scss中的變數配置,可以進行專案的顏色、字型大小統一更改(換膚),有利於後期專案的維護。

推薦:

$--color-success: #67C23A;
$--color-warning: #E6A23C;
$--color-danger: #F56C6C;
$--color-info: #909399;
複製程式碼

4.2、@import 匯入樣式檔案

scss中的@import規則在生成css檔案時就把相關檔案匯入進來。這意味著所有相關的樣式被歸納到了同一個css檔案中,而無需發起額外的下載請求,在構建我們自己的元件庫時推薦使用。

@import "./base.scss";
@import "./pagination.scss";
@import "./dialog.scss";
@import "./autocomplete.scss";
@import "./dropdown.scss";
@import "./dropdown-menu.scss";

複製程式碼

4.3、區域性檔案命名的使用

scss區域性檔案的檔名以下劃線開頭。這樣,scss就不會在編譯時單獨編譯這個檔案輸出css,而只把這個檔案用作匯入。

推薦:

前端團隊程式碼評審 CheckList 清單

4.4、父選擇器識別符號 & 實現BEM 命令規範

scss的巢狀和父選擇器識別符號 & 能解決BEM命名的冗長,且使樣式可讀性更高。

推薦:

.el-input {
​  display: block;
​  &__inner {
​     text-align: center;
​  }
}複製程式碼

4.5、@mixin 混合器的使用

mixin混合器用來實現大段樣式的重用,減少程式碼的冗餘,且支援傳參。

@mixin button-size($padding-vertical, $padding-horizontal, $font-size, $border-radius) {
  padding: $padding-vertical $padding-horizontal;
  font-size: $font-size;
  border-radius: $border-radius;
  &.is-round {
​    padding: $padding-vertical $padding-horizontal;
  }
}

  @include m(medium) {
​    @include button-size($--button-medium-padding-vertical, $--button-medium-padding-horizontal, $--button-medium-font-size, $--button-medium-border-radius);   
  }

  @include m(small) {
​    @include button-size($--button-small-padding-vertical, $--button-small-padding-horizontal, $--button-small-font-size, $--button-small-border-radius);
  } 

複製程式碼

4.6、@extend 指令的使用

(1)使用@extend產生 DRY CSS風格的程式碼(Don't repeat yourself)

(2)@mixin主要的優勢就是它能夠接受引數。如果想傳遞引數,你會很自然地選擇@mixin而不是@extend

推薦:

.common-mod {
  height: 250px;
  width: 50%;
  background-color: #fff;
  text-align: center;
}

 .show-mod--right {
​   @extend .common-mod;
​   float: right;
​ }

​.show-mod--left {
​   @extend .common-mod;
​}

複製程式碼

4.7、#{} 插值的使用

插值能動態定義類名的名稱,當有兩個頁面的樣式類似時,我們會將類似的樣式抽取成頁面混合器,但兩個不同的頁面樣式的命名名稱根據BEM命名規範不能一樣,這時我們可使用插值進行動態命名。

推薦:

@mixin home-content($class) {
  .#{$class} {
​    position: relative;
​    background-color: #fff;
​    overflow-x: hidden;
​    overflow-y: hidden;

​    &--left {
​      margin-left: 160px;
​    }

​    &--noleft {
​      margin-left: 0;
​    }
  }
}

複製程式碼

 4.8、each遍歷、map資料型別、@mixin/@include混合器、#{}插值 結合使用

可通過each遍歷、map資料型別、@mixin/@include混合器、#{} 插值 結合使用,從而減少冗餘程式碼,使程式碼更精簡。

推薦:

$img-list: (
   (xlsimg, $papers-excel),
   (xlsximg, $papers-excel),
   (gifimg, $papers-gif),
   (jpgimg, $papers-jpg),
   (mp3img, $papers-mp3),
   (mp4img, $papers-mp3),
   (docimg, $papers-word),
   (docximg, $papers-word),
   (rarimg, $papers-zip),
   (zipimg, $papers-zip),
   (unknownimg, $papers-unknown)
);

@each $label, $value in $img-list {
  .com-hwicon__#{$label} {
​    @include commonImg($value);
  }
}

複製程式碼

4.9、scss 自帶函式的應用

scss自帶函式的應用,從而進行相關的計算,例如 mix函式的使用如下。

 @include m(text) {
​    &:hover,
​    &:focus {
​      color: mix($--color-white, $--color-primary, $--button-hover-tint-percent);
​      border-color: transparent;
​      background-color: transparent;
​    }

​    &:active {
​      color: mix($--color-black, $--color-primary, $--button-active-shade-percent);
​      border-color: transparent;
​      background-color: transparent;
​    }
}

複製程式碼

4.10、gulp-sass的使用

gulp-sass外掛能實時監測scss程式碼檢查其語法錯誤並將其編譯成css程式碼,幫助開發人員檢查scss語法的準確性,且其是否符合我們的預期,相關配置如下:

gulp.task('gulpsass', function() {
  return gulp.src('src/style/components/hwIcon.scss')
​    .pipe(gulpsass().on('error', gulpsass.logError))
​    .pipe(gulp.dest('src/style/dest'));
});

gulp.task('watch', function() {
  gulp.watch('src/style/components/hwIcon.scss', ['gulpsass']);
});
複製程式碼

五、Vue 推薦寫法

5.1、元件名為多個單詞

我們開發過程中自定義的元件的名稱需要為多個單詞,這樣做可以避免跟現有的以及未來的HTML元素相沖突,因為所有的 HTML 元素名稱都是單個單詞的。

推薦:

Vue.component('todo-item', {
  // ...
})

export default {
  name: 'TodoItem',
  // ...
}複製程式碼

不推薦:

Vue.component('todo', {
  // ...
})

export default {
  name: 'Todo',
  // ...
}

複製程式碼

5.2、元件的 data 必須是一個函式

當在元件中使用 data 屬性的時候 (除了 new Vue 外的任何地方),它的值必須是返回一個物件的函式。 因為如果直接是一個物件的話,子元件之間的屬性值會互相影響。

推薦:

export default {
  data () {
​    return {
​      foo: 'bar'
​    }
  }
}複製程式碼

不推薦:

export default {
  data: {
​    foo: 'bar'
  }
}複製程式碼

5.3、Prop定義應該儘量詳細

prop 的定義應該儘量詳細,至少需要指定其型別。

推薦:

props: {
  status: String
}

// 更好的做法!
props: {
  status: {
​    type: String,
​    required: true,
​    validator: function (value) {
​      return [
​        'syncing',
​        'synced',
​        'version-conflict',
​        'error'
​      ].indexOf(value) !== -1
​    }
  }
}複製程式碼

不推薦:

props: ['status'] 複製程式碼

5.4、為 v-for 設定鍵值

v-for 中總是有設定 key 值。在元件上總是必須用 key 配合 v-for,以便維護內部元件及其子樹的狀態。

推薦:

<ul>
  <li
​    v-for="todo in todos"
​    :key="todo.id">
​    {{ todo.text }}
  </li>
</ul>複製程式碼

不推薦:

<ul>
  <li v-for="todo in todos">
​    {{ todo.text }}
  </li>
</ul>複製程式碼


5.5、完整單詞的元件名

元件名應該傾向於完整單詞而不是縮寫,編輯器中的自動補全已經讓書寫長命名的代價非常之低了,而其帶來的明確性卻是非常寶貴的。不常用的縮寫尤其應該避免。

推薦:

components/ 
|- StudentDashboardSettings.vue 
|- UserProfileOptions.vue 複製程式碼

不推薦:

components/ 
|- SdSettings.vue 
|- UProfOpts.vue 複製程式碼

5.6、多個特性元素的每個特性分行

JavaScript 中,用多行分隔物件的多個屬性是很常見的最佳實踐,因為這樣更易讀。

推薦:

<MyComponent
  foo="a"
  bar="b"
  baz="c"
/>複製程式碼

不推薦:

<MyComponent foo="a" bar="b" baz="c"/> 複製程式碼

5.7、模板中簡單的表示式

元件模板應該只包含簡單的表示式,複雜的表示式則應該重構為計算屬性或方法。複雜表示式會讓你的模板變得不那麼宣告式。我們應該儘量描述應該出現的是什麼,而非如何計算那個值。而且計算屬性和方法使得程式碼可以重用。

推薦:

<!-- 在模板中 -->
{{ normalizedFullName }}

// 複雜表示式已經移入一個計算屬性
computed: {
  normalizedFullName: function () {
​    return this.fullName.split(' ').map(function (word) {
​      return word[0].toUpperCase() + word.slice(1)
​    }).join(' ')
  }
}複製程式碼

不推薦:

{{
  fullName.split(' ').map(function (word) {
​    return word[0].toUpperCase() + word.slice(1)
  }).join(' ')
}}複製程式碼

5.8、簡單的計算屬性

應該把複雜計算屬性分割為儘可能多的更簡單的屬性。

推薦:

computed: {
  basePrice: function () {
​    return this.manufactureCost / (1 - this.profitMargin)
  },
  discount: function () {
​    return this.basePrice * (this.discountPercent || 0)
  },
  finalPrice: function () {
​    return this.basePrice - this.discount
  }
}複製程式碼

不推薦:

computed: {
  price: function () {
​    var basePrice = this.manufactureCost / (1 - this.profitMargin)
​    return (
​      basePrice -
​      basePrice * (this.discountPercent || 0)
​    )
  }
}複製程式碼

5.9、指令縮寫

指令推薦都使用縮寫形式,(用 : 表示 v-bind: 、用 @ 表示 v-on: 和用 # 表示 v-slot:)。

推薦:

<input
  @input="onInput"
  @focus="onFocus"
>複製程式碼

不推薦:

<input
  v-on:input="onInput"
  @focus="onFocus"
>複製程式碼

5.10、標籤順序保持一致

單檔案元件應該總是讓標籤順序保持為 <template> 、<script>、 <style> 。

推薦:

<!-- ComponentA.vue -->

<template>...</template>
<script>/* ... */</script>
<style>/* ... */</style>複製程式碼

不推薦:

<!-- ComponentA.vue -->

<template>...</template>
<style>/* ... */</style>
<script>/* ... */</script>複製程式碼

5.11、元件之間通訊

父子元件的通訊推薦使用 propemit ,而不是this.​$parent或改變 prop

兄弟元件之間的通訊推薦使用 EventBus(on),而不是濫用 vuex

祖孫元件之間的通訊推薦使用​listeners provide / inject(依賴注入) ,而不是濫用 vuex

5.12、頁面跳轉資料傳遞

頁面跳轉,例如 A 頁面跳轉到 B 頁面,需要將 A 頁面的資料傳遞到 B 頁面,推薦使用 路由引數進行傳參,而不是將需要傳遞的資料儲存 vuex,然後在 B 頁面取出 vuex的資料,因為如果在 B 頁面重新整理會導致 vuex 資料丟失,導致 B 頁面無法正常顯示資料。

推薦:

let id = ' 123';
this.$router.push({name: 'homeworkinfo', query: {id:id}}); 複製程式碼

 5.13、script 標籤內部宣告順序

script 標籤內部的宣告順序如下:

data > prop > components > filter > computed >  watch > 
鉤子函式(鉤子函式按其執行順序)> methods複製程式碼

5.14、計算屬性 VS 方法 VS 偵聽器

  • (1)推薦使用計算屬性:計算屬性基於響應式依賴進行快取,只在相關響應式依賴發生改變時它們才會重新求值;相比之下,每次呼叫方法都會再次執行方法;

  • (2)推薦使用計算屬性:而不是根據 Watch 偵聽屬性,進行回撥; 但是有計算屬性做不到的:當需要在資料變化時執行非同步或開銷較大的操作時,偵聽器是最有用的。

5.15、v-if VS v-show

  • v-if 是“真正”的條件渲染,因為它會確保在切換過程中條件塊內的事件監聽器和子元件適當地被銷燬和重建。 v-if 也是惰性的:如果在初始渲染時條件為假,則什麼也不做——直到條件第一次變為真時,才會開始渲染條件塊。

  • 相比之下,v-show 就簡單得多——不管初始條件是什麼,元素總是會被渲染,並且只是簡單地基於 CSS 的屬性 display 進行切換。

推薦:

如果執行時,需要非常頻繁地切換,推薦使用 v-show 比較好;如果在執行時,條件很少改變,則推薦使用 v-if 比較好。

六、團隊其它規範

6.1、儘量不手動操作 DOM

因為團隊現在使用 vue 框架,所以在專案開發中儘量使用 vue 的特性去滿足我們的需求,儘量(不到萬不得已)不要手動操作DOM,包括:增刪改dom元素、以及更改樣式、新增事件等。

6.2、刪除棄用程式碼

很多時候有些程式碼已經沒有用了,但是沒有及時去刪除,這樣導致程式碼裡面包括很多註釋的程式碼塊,好的習慣是提交程式碼前記得刪除已經確認棄用的程式碼,例如:一些除錯的console語句、無用的棄用程式碼。

6.3、保持必要的註釋

程式碼註釋不是越多越好,保持必要的業務邏輯註釋,至於函式的用途、程式碼邏輯等,要通過語義化的命令、簡單明瞭的程式碼邏輯,來讓閱讀程式碼的人快速看懂。


辛苦整理良久,如果對你有幫助,還望手動點贊鼓勵~~~~~~

github地址為:github.com/fengshi123/…,如果喜歡或者有所啟發,請幫忙給個 star ~,對作者也是一種鼓勵。


參考文獻

1、clean-code-javascriptgithub.com/ryanmcdermo…

2、SCSS — 縮減50%的樣式程式碼 : juejin.im/post/5c4888…

3、vue cookbookcn.vuejs.org/v2/cookbook…


相關文章