JS編程規範指南

原文:github.com/ryanmcdermott/clean-code-javascript
說明:本文翻譯自 github 上的一個項目,只取部分精華。

1、變量

用有意義且經常使用的單詞命名

//Bad
const yyyymmdstr=moment().format('YYYY/MM/DD');
//Good
const currentDate=moment().format('YYYY/MM/DD');

保持統一

對同一類型的變量使用相同的命名保持統一:javascript

//Bad:
getUserInfo();
getClientData();
getCustomerRecord();
//Good:
getUser();

每一個常量(全大寫)都該命名

能夠用 ESLint 檢測代碼中未命名的常量。html

//Bad:
//其餘人知道86400000的意思嗎?
setTimeout(blastoff,864000);
//Good:
const MILLISECOND_IN_A_DAY=86400000;
setTimeout(blastoff,MILLISECOND_IN_A_DAY);

避免無心義的命名

既然建立了一個 car 對象,就沒有必要把它的顏色命名爲 carColor。java

//Bad:
const car={
      carMake:'Honda',
      carModel:'Accord',
      carColor:'Blue'  
};
function paintCar(car){
       car.carColor='Red'; 
}
//Good:
const car={
      make:'Honda',
      model:'Accord',
      color:'Blue'
}; 
function paintCar(car){
       car.color='Red'; 
}

傳參使用默認值

//Bad:
function createMicrobrewery(name){
      const breweryName=name||'Hipster Brew Co.';  
      // ...
}    
//Good:
function createMicrobrewery(name='Hipster Brew Co.'){
      // ...      
}    

2、函數

函數參數( 最好 2 個或更少 )

若是參數超過兩個,建議使用 ES6 的解構語法,不用考慮參數的順序。node

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

createMenu({
      title:'Foo',
      body:'Bar',
      buttonText:'Baz',
      cancellable:true
});

一個方法只作一件事情

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

//Bad:
function emailClients(clients){
      clients.foreach(client =>{
           const clientRecord = database.lookup(client);
           if(clientRecord.isActive()){
                email(client);
           }
      });
}
//Good:
function emailActiveClients(clients){
     clients
          .filter(isActiveClient)
          .forEach(email);
}
function isActiveClient(client){
     const clientRecord = database.lookup(client);
     return clientRecord.isActive();
}

函數名上體現它的做用

//Bad:
function addToDate(date,month){
     // ...
}
const date = new Date();
//很難知道是把什麼加到日期中
addToDate(date,1);

//Good:
function addMonthToDate(month,date){
     // ...
}
const date = new Date();
addMonthToDate(1,date);

刪除重複代碼,合併類似函數

不少時候雖然是同一個功能,但因爲一兩個不一樣點,讓你不得不寫兩個幾乎相同的函數。github

/Bad:
function showDeveloperList(developers){
     developers.forEach((developer)=>{
           const expectedSalary = developer.calculateExpectedSalary;
           const experience = developer.getExperience();
           const githubLink = developer.getGithubLink();
           const data={
                expectedSalary,
                experience,
                githubLink
           };
           render(data);
     });  
}
function showManagerList(managers){
     managers.forEach((manager)=>{
            const expectedSalary = manager.calculateExpectedSalary();
            const experience = manager.getExperience();
            const portfolio = manager.getMBAProjects();
            const data={
                expectedSalary,
                experience,
                portfolio
            };
            render(data);
     });
}
//Good:
function showEmployeeList(employees){
     employees.forEach((employee)=>{
          const expectedSalary = employee.getExpectedSalary();
          const experience = employee.getExperience();
          const data = {
              expectedSalary,
              experience,
          }
          switch(employee.type){
              case  'develop':
                      data.githubLink=employee.getGithubLink();
                      break;
              case 'manager':
                      data.portfolio = employee.getMBAProjects();
                      break;
          }
          render(data);
     });
}

使用 Object.assign 設置默認屬性

//Bad:
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);

//Good:
const menuConfig = {
   title: 'Order',
   //不包含body
   buttonText: 'Send',
   cancellable: true
};
function createMenu(config){
   config = Object.assign({
       title: 'Foo',
       body: 'Bar',
       buttonText: 'Baz',
       cancellable:true
   },config);

   // config:{title: "order",body:"Bar",buttonText:"Send",cancellable:true}
   // ...
}

儘可能不要寫全局方法

在 JavaScript 中,永遠不要污染全局,會在生產環境中產生難以預料的 bug。舉個例子,好比你在 Array.prototype 上新增一個 diff 方法來判斷兩個數組的不一樣。而你同事也打算作相似的事情,不過他的 diff 方法是用來判斷兩個數組首位元素的不一樣。很明顯大家方法會產生衝突,遇到這類問題咱們能夠用 ES2015/ES6 的語法來對 Array 進行擴展。數組

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

//Good:
class SuperArray extends Array{
   diff(comparisonArray){
      const hash = new Set(comparisonArray);
      return this.filter(elem=> !hash.has(elem));
   }
}

儘可能別用「非」條件句

//Bad:
function isDOMNodeNotPresent(node){
   // ...  
}

if (!isDOMNodePresent(node)){
   // ...  
}

//Good:
function isDOMNodePresent(node){
   // ...
}
if(isDOMNodePresent(node)){
  // ...
}

不要過分優化

現代瀏覽器已經在底層作了不少優化,過去的不少優化方案都是無效的,會浪費你的時間。promise

//Bad:
// 現代瀏覽已對此(緩存list.length)作了優化。
for(let i = 0, len = list.length;i < len;i++){
   // ...
}

//Good:
for(let i = 0; i< list.length; i++){
   // ...
} 

刪除棄用代碼

棄用代碼不用註釋,直接刪除就對了瀏覽器

3、類

使用 ES6 的 class

在 ES6 以前,沒有類的語法,只能用構造函數的方式模擬類,可讀性很是差。緩存

//Good:
// 動物
class Animal{
   constructor(age){
       this.age = age
   };
   move()  {};
}

// 哺乳動物
class Mammal extends Animal{
   constructor(age, furcolor){
       super(age);
       this.furColor = furColor;
   };
   liveBirth() {};
}

//人類
class Human extends Mammal{
   constructor(age, furColor, languageSpoken){
       super(age,furColor);
       this.languageSpoken=languageSpoken;
   }
   speak() {};
}

使用鏈式調用

這種模式至關有用,能夠在不少庫中都有使用。它讓你的代碼簡潔優雅。

class Car{
   constructor(make,model,color){
       this.make = make;
       this.model = model;
       this.color = color;
   }
   
   setMake(make){
      this.make = make;
   }
   
   setModel(model){
      this.model = model;
   }
   
   setColor(color){
      this.color = color;
   }

   save(){
      console.log(this.make, this.model., this.color);
   }
}

// Bad:
const car = new Car('Ford','F-150','red');
car.setColor('pink');
car.save();

//Good:
const car = new Car('Ford','F-150','red')
                         .setColor('pink')
                         .save();

4、異步

使用 promise 或者 Async/Await 代替回調

//Bad:
get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin',(requestErr,response) => {
    if(requestErr){
       consoloe.error(requestErr);
    }else{
        writeFile('article.html',response.body,(writeErr) => {
            if(writeErr){
               console.error(writeErr);
            }else {
                 console.log('File written');
            }
        })
    }
});

//Good:
get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin')
     .then((response) => {
         return writeFile('article.html' ,response);
     })
     .then( (response) => {
         console.log('File written');
     })
     .catch( (err) => {
         console.error(err);
     });

//perfect:
async function getCleanCodeArticle(){
   try{
      const response = await get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin');
      await writeFile('artical.html',response);
      console.log('File written');
   }catch (err){
     console.error(err);
   }
}
相關文章
相關標籤/搜索