原文:github.com/ryanmcdermott/clean-code-javascript
說明:本文翻譯自 github 上的一個項目,只取部分精華。
//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.'){ // ... }
若是參數超過兩個,建議使用 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); }); }
//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++){ // ... }
棄用代碼不用註釋,直接刪除就對了瀏覽器
在 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();
//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); } }