為什么同事寫的代碼那么優雅~

大家好,我是若川,誠邀你進群交流學習。今天分享一篇相對輕松的代碼簡潔之道。學習源碼系列、面試、年度總結、JS基礎系列


內容出自《代碼整潔之道》、Alex Kondov[1]的博文tao-of-react[2]和《Clean Code of Javascript》

image.png

代碼整潔有什么用?

image.png
  1. 思路清晰,降低bug幾率

  2. 更容易維護,利于團隊協作

  3. 看起來舒服,提高效率

  4. ......

軟件質量與代碼整潔度成正比 --Robert.C.Martin

軟件設計3R層次結構:readable, reusable, and refactorable[3] 可讀性、可重用性、可重構性

下面這些原則是作者提出的一些最佳實踐,但不是強制約束

關于命名

1.使用有意義且易讀的變量名

?????const?yyyymmdstr?=?moment().format("YYYY/MM/DD");?????const?currentDate?=?moment().format("YYYY/MM/DD");

2.使用有意義的變量代替數組下標

?????
const?address?=?"One?Infinite?Loop,?Cupertino?95014";
const?cityZipCodeRegex?=?/^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
saveCityZipCode(address.match(cityZipCodeRegex)[1],address.match(cityZipCodeRegex)[2]
);????
const?address?=?"One?Infinite?Loop,?Cupertino?95014";
const?cityZipCodeRegex?=?/^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
const?[_,?city,?zipCode]?=?address.match(cityZipCodeRegex)?||?[];
saveCityZipCode(city,?zipCode);

3.變量名要簡潔,不要附加無用信息

?????
const?Car?=?{carMake:?"Honda",carModel:?"Accord",carColor:?"Blue"
};
function?paintCar(car,?color)?{car.carColor?=?color;
}????
const?Car?=?{make:?"Honda",model:?"Accord",color:?"Blue"
};
function?paintCar(car,?color)?{car.color?=?color;
}

4.消除魔術字符串

?????setTimeout(blastOff,?86400000);?????const?MILLISECONDS_PER_DAY?=?60?*?60?*?24?*?1000;?//86400000;
setTimeout(blastOff,?MILLISECONDS_PER_DAY);

5.使用默認參數替代短路運算符

????
function?createMicrobrewery(name)?{const?breweryName?=?name?||?"Hipster?Brew?Co.";//?...
}?????
function?createMicrobrewery(name?=?"Hipster?Brew?Co.")?{//?...
}

關于函數

1.一個函數只做一件事的好處在于易于理解、易于測試。

????
function?emailClients(clients)?{clients.forEach(client?=>?{const?clientRecord?=?database.lookup(client);if?(clientRecord.isActive())?{email(client);}});
}?????
function?emailActiveClients(clients)?{clients.filter(isActiveClient).forEach(email);
}
function?isActiveClient(client)?{const?clientRecord?=?database.lookup(client);return?clientRecord.isActive();
}---------------------分割線-----------------------????
function?createFile(name,?temp)?{if?(temp)?{fs.create(`./temp/${name}`);}?else?{fs.create(name);}
}?????
function?createFile(name)?{fs.create(name);
}
function?createTempFile(name)?{createFile(`./temp/${name}`);
}

2.函數參數不多于2個,如果有很多參數就利用object傳遞,并使用解構。

推薦使用解構的幾個原因:

  1. 看到函數簽名可以立即了解有哪些參數

  2. 解構能克隆傳遞到函數中的參數對象的值(淺克隆),有助于防止副作用.

  3. linter可以提示有哪些參數未被使用

????
function?createMenu(title,?body,?buttonText,?cancellable)?{//?...
}
createMenu("Foo",?"Bar",?"Baz",?true);?????
function?createMenu({?title,?body,?buttonText,?cancellable?})?{//?...
}
createMenu({title:?"Foo",body:?"Bar",buttonText:?"Baz",cancellable:?true
});

3.函數名應該直接反映函數的作用

????
function?addToDate(date,?month)?{//?...
}
const?date?=?new?Date();
//?It's?hard?to?tell?from?the?function?name?what?is?added
addToDate(date,?1);?????
function?addMonthToDate(month,?date)?{//?...
}
const?date?=?new?Date();
addMonthToDate(1,?date);

4.一個函數的抽象層級不要太多,如果你的函數做了太多事,就需要把它拆分成多個函數

????
function?parseBetterJSAlternative(code)?{const?REGEXES?=?[//?...];const?statements?=?code.split("?");const?tokens?=?[];REGEXES.forEach(REGEX?=>?{statements.forEach(statement?=>?{//?...});});const?ast?=?[];tokens.forEach(token?=>?{//?lex...});ast.forEach(node?=>?{//?parse...});
}?????
function?parseBetterJSAlternative(code)?{const?tokens?=?tokenize(code);const?syntaxTree?=?parse(tokens);syntaxTree.forEach(node?=>?{//?parse...});
}
function?tokenize(code)?{const?REGEXES?=?[//?...];const?statements?=?code.split("?");const?tokens?=?[];REGEXES.forEach(REGEX?=>?{statements.forEach(statement?=>?{tokens.push(/*?...?*/);});});return?tokens;
}
function?parse(tokens)?{const?syntaxTree?=?[];tokens.forEach(token?=>?{syntaxTree.push(/*?...?*/);});return?syntaxTree;
}

5.減少重復代碼

????
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);});
}?????
function?showEmployeeList(employees)?{employees.forEach(employee?=>?{const?expectedSalary?=?employee.calculateExpectedSalary();const?experience?=?employee.getExperience();const?data?=?{expectedSalary,experience};switch?(employee.type)?{case?"manager":data.portfolio?=?employee.getMBAProjects();break;case?"developer":data.githubLink?=?employee.getGithubLink();break;}render(data);});
}

6.盡量使用純函數 (函數式編程,not命令式編程)

????
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;
}?????
const?programmerOutput?=?[{name:?"Uncle?Bobby",linesOfCode:?500},{name:?"Suzie?Q",linesOfCode:?1500},{name:?"Jimmy?Gosling",linesOfCode:?150},{name:?"Gracie?Hopper",linesOfCode:?1000}
];
const?totalOutput?=?programmerOutput.reduce((totalLines,?output)?=>?totalLines?+?output.linesOfCode,0
);

7.注意函數的副作用

????
const?addItemToCart?=?(cart,?item)?=>?{cart.push({?item,?date:?Date.now()?});
};?????
const?addItemToCart?=?(cart,?item)?=>?{return?[...cart,?{?item,?date:?Date.now()?}];
};

8.不要過度優化

現代瀏覽器在運行時進行了大量的優化。很多時候,如果你再優化,那就是在浪費時間。

????
//?On?old?browsers,?each?iteration?with?uncached?`list.length`?would?be?costly
//?because?of?`list.length`?recomputation.?In?modern?browsers,?this?is?optimized.
for?(let?i?=?0,?len?=?list.length;?i?<?len;?i++)?{//?...
}?????
for?(let?i?=?0;?i?<?list.length;?i++)?{//?...
}

關于注釋

1.Comments are an apology, not a requirement. Good code mostly documents itself.

好的代碼是自注釋的

????
function?hashIt(data)?{//?The?hashlet?hash?=?0;//?Length?of?stringconst?length?=?data.length;//?Loop?through?every?character?in?datafor?(let?i?=?0;?i?<?length;?i++)?{//?Get?character?code.const?char?=?data.charCodeAt(i);//?Make?the?hashhash?=?(hash?<<?5)?-?hash?+?char;//?Convert?to?32-bit?integerhash?&=?hash;}
}?????
function?hashIt(data)?{let?hash?=?0;const?length?=?data.length;for?(let?i?=?0;?i?<?length;?i++)?{const?char?=?data.charCodeAt(i);hash?=?(hash?<<?5)?-?hash?+?char;//?Convert?to?32-bit?integerhash?&=?hash;}
}

2.git能做的事不要寫在注釋里

????
/***?2016-12-20:?Removed?monads,?didn't?understand?them?(RM)*?2016-10-01:?Improved?using?special?monads?(JP)*?2016-02-03:?Removed?type-checking?(LI)*?2015-03-14:?Added?combine?with?type-checking?(JR)*/
function?combine(a,?b)?{return?a?+?b;
}?????
function?combine(a,?b)?{return?a?+?b;
}

關于組件

1.盡可能使用函數組件

函數式組件有更簡單的語法,沒有生命周期函數,構造函數。同樣的邏輯和可靠性,函數式組件可以用更少的代碼完成。

?????
class?Counter?extends?React.Component?{state?=?{counter:?0,}constructor(props)?{super(props)this.handleClick?=?this.handleClick.bind(this)}handleClick()?{this.setState({?counter:?this.state.counter?+?1?})}render()?{return?(<div><p>counter:?{this.state.counter}</p><button?onClick={this.handleClick}>Increment</button></div>)}
}
????
function?Counter()?{const?[counter,?setCounter]?=?useState(0)handleClick?=?()?=>?setCounter(counter?+?1)return?(<div><p>counter:?{counter}</p><button?onClick={handleClick}>Increment</button></div>)
}

2.函數組件中剝離邏輯代碼

盡可能的把邏輯從組件中剝離出去,可以把必要的值用參數的形式傳給工具類函數。在函數組件外組織你的邏輯讓你能夠更簡單的去追蹤 bug 和擴展你的功能。

????
export?default?function?Component()?{const?[value,?setValue]?=?useState('')function?isValid()?{//?...}return?(<><inputvalue={value}onChange={e?=>?setValue(e.target.value)}onBlur={validateInput}/><buttononClick={()?=>?{if?(isValid)?{//?...}}}>Submit</button></>)
}?????
function?isValid(value)?{//?...
}
export?default?function?Component()?{const?[value,?setValue]?=?useState('')return?(<><inputvalue={value}onChange={e?=>?setValue(e.target.value)}onBlur={validateInput}/><buttononClick={()?=>?{if?(isValid(value))?{//?...}}}>Submit</button></>)
}

3.控制組件長度,減少UI耦合

函數組件也是函數,同樣要控制長度,如果組件太長,就要拆成多個組件

????
function?Filters({?onFilterClick?})?{return?(<><p>Book?Genres</p><ul><li><div?onClick={()?=>?onFilterClick('fiction')}>Fiction</div></li><li><div?onClick={()?=>?onFilterClick('classics')}>Classics</div></li><li><div?onClick={()?=>?onFilterClick('fantasy')}>Fantasy</div></li><li><div?onClick={()?=>?onFilterClick('romance')}>Romance</div></li></ul></>)
}//??????Use?loops?and?configuration?objects
const?GENRES?=?[{identifier:?'fiction',name:?Fiction,},{identifier:?'classics',name:?Classics,},{identifier:?'fantasy',name:?Fantasy,},{identifier:?'romance',name:?Romance,},
]function?Filters({?onFilterClick?})?{return?(<><p>Book?Genres</p><ul>{GENRES.map(genre?=>?(<li><div?onClick={()?=>?onFilterClick(genre.identifier)}>{genre.name}</div></li>))}</ul></>)
}

4.盡量避免函數組件內再定義函數組件

不要在一個函數組件中再去書寫一個函數組件。一個函數組件應該僅僅是一個函數。函數組件內部再定義函數組件,意味著內部的函數組件能夠通過作用域訪問到外層組件所有的 state 和 props,這樣會使內部定義組件不可靠。把內部的組件移到外部,避免閉包和作用域的影響。

//??????Don't?write?nested?render?functions
function?Component()?{function?renderHeader()?{return?<header>...</header>}return?<div>{renderHeader()}</div>
}
//??????Extract?it?in?its?own?component
import?Header?from?'@modules/common/components/Header'
function?Component()?{return?(<div><Header?/></div>)
}

5.優化props

控制props數量、聚合props、完善渲染條件

  1. 如何把控 props 的量是一個值得商榷的問題。但是一個組件傳遞越多的 props 意味著它做的事情越多這是共識。當 props 達到一定數量的時候,意味著這個組件做的事情太多了。當props的數量達到5個以上的時候,這個組件就需要被拆分了。在某些極端諸如輸入類型組件的情況下,可能擁有過多的props,但在通常情況下5個props能夠滿足大部分組件的需求。

提示:一個組件擁有越多的 props,越容易被 rerender。

  1. 一些場景下使用短路語法來進行條件渲染可能導致期望之外的問題,有可能會渲染一個 0 在界面上。避免這種情況發生,盡量使用三元操作符。盡管短路操作符能使代碼變得簡潔,但是三元操作符能夠保證渲染的正確性。

//??????Try?to?avoid?short-circuit?operators
function?Component()?{const?count?=?0return?<div>{count?&&?<h1>Messages:?{count}</h1>}</div>
}
//??????Use?a?ternary?instead
function?Component()?{const?count?=?0return?<div>{count???<h1>Messages:?{count}</h1>?:?null}</div>
}

關于其他

1.把組件放入單獨的文件夾中

//??????Don't?keep?all?component?files?together
├──?components├──?Header.jsx├──?Header.scss├──?Header.test.jsx├──?Footer.jsx├──?Footer.scss├──?Footer.test.jsx//??????Move?them?in?their?own?folder
├──?components├──?Header├──?index.js├──?Header.jsx├──?Header.scss├──?Header.test.jsx├──?Footer├──?index.js├──?Footer.jsx├──?Footer.scss├──?Footer.test.jsx

2.盡量使用絕對路徑

使用絕對路徑可以在移動一個文件的時候能夠盡量少的更改其它文件。絕對路徑也能讓你對所有依賴文件的出處一目了然。

(完)


最近組建了一個江西人的前端交流群,如果你是江西人可以加我微信?ruochuan12?私信 江西 拉你進群。


推薦閱讀

我在阿里招前端,該怎么幫你(可進面試群)
畢業年限不長的前端焦慮和突破方法

前端搶飯碗系列之Vue項目如何做單元測試
老姚淺談:怎么學JavaScript?

·················?若川簡介?·················

你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》多篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經寫了7篇,點擊查看年度總結。
同時,活躍在知乎@若川,掘金@若川。致力于分享前端開發經驗,愿景:幫助5年內前端人走向前列。

點擊上方卡片關注我、加個星標

今日話題

略。歡迎分享、收藏、點贊、在看我的公眾號文章~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/275704.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/275704.shtml
英文地址,請注明出處:http://en.pswp.cn/news/275704.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[轉]讓你賺大錢成富翁的4個投資習慣

本文轉自&#xff1a;http://bbs.jrj.com.cn/msg,68723793.html 第一條&#xff1a;對自己進行投資  這是最大最大的投資&#xff0c;當然收獲也是最為豐盛的。藝不壓身&#xff0c;這句話非常有哲理。朋友今年27歲&#xff0c;可是毫不夸張地說&#xff0c;他已經具有了百萬…

thymeleaf th:href url傳遞多參數

<a th:href"{/teacherShowMember(class_id${class.classId}&#xff0c;class_name${class.className})}"></a> thymeleaf使用&#xff08;,,&#xff09;的形式解析多個參數,結合${}放置變量十分方便 傳統URL傳遞多參數使用&#xff1f;&拼接 <a…

spring 加載java類_在Spring中基于Java類進行配置的完整步驟

在Spring中基于Java類進行配置的完整步驟發布于 2020-7-7|復制鏈接基于Java配置選項&#xff0c;可以編寫大多數的Spring不用配置XML&#xff0c;下面前言JavaConfig 原來是 Spring 的一個子項目&#xff0c;它通過 Java 類的方式提供 Bean 的定義信息&#xff0c;在 Spring4 的…

2021 年最值得了解的 Node.js 工具(下)

大家好&#xff0c;我是若川&#xff0c;誠邀你加群長期交流。今天分享一篇用得上的 node 庫。下篇。鏈接地址&#xff1a;https://github.com/huaize2020/awesome-nodejs。上篇是&#xff1a;2021 年最值得了解的 Node.js 工具?前言&#xff1a;前端時間分享了這些node開源工…

技術點

前端所用技術 后臺頁面 感謝 H-ui、FlatLab 提供靜態頁面支持Ztree&#xff1a;jQuery樹插件DataTables&#xff1a;jQuery表格插件Layer&#xff1a;web彈層組件Distpicker&#xff1a;中國省市區地址三級聯動插件KindEditor&#xff1a;富文本編輯器 簡潔方便 沒UEditor那么多…

掃描java類文件_java遞歸與非遞歸實現掃描文件夾下文件的實例代碼

java遞歸與非遞歸實現掃描文件夾下所有文件java掃描指定文件夾下面的所有文件&#xff0c;供大家參考&#xff0c;具體內容如下掃描一個文件夾下面的所有文件&#xff0c;因為文件夾的層數沒有限制可能多達幾十層幾百層&#xff0c;通常會采用兩種方式來遍歷指定文件夾下面的所…

【阿里內部應用】基于Blink為新商業調控打造實時大數據交互查詢服務

基于Blink為新商業調控打造實時大數據交互查詢服務 案例與解決方案匯總頁&#xff1a;阿里云實時計算產品案例&解決方案匯總從IT到DT、從電商到新商業&#xff0c;阿里巴巴的每個細胞都存在大數據的DNA&#xff0c;如何挖掘大數據的價值成為搶占未來先機的金鑰匙&#xff0…

Vite 的好與壞

大家好&#xff0c;我是若川&#xff0c;誠邀你進群交流學習。今天分享一篇關于Vite的文章。學習源碼系列、面試、年度總結、JS基礎系列。全文 3000 字&#xff0c;歡迎點贊關注轉發一、Vite 是什么2020年4月&#xff0c;尤大大發了這么一個推&#xff1a;隨后&#xff0c;2021…

Windows phone 7新開發工具發布

春節假期已經接近尾聲. 馬上第一個工作日就要來臨. 春節真的不再是一個簡簡單單的節日. 有時讓人感到欣喜 這意味這一年的忙碌都會因為這個節日的到來而畫上一個終止符.面臨一個不長也不短的假期.眼下的一年翻過去 新的一年即將到來. 似乎一切都可以重新開始. 有時又令人感到無…

opentaps mysql_opentaps 1.4 聯接 mysql 筆記

opentaps 1.4 連接 mysql 筆記一、安裝 MySQ 略...二、創建MySQL Database opentaps ERP CRM1.mysql -u root -h 127.0.0.1 -p 2.mysql>create database opentaps default CHARACTER SET utf8 COLLATE utf8_general_ci;3.mysql>create user opentaps;4.mysql>grant …

這10道springboot常見面試題你需要了解下

1、什么是Spring Boot&#xff1f;多年來&#xff0c;隨著新功能的增加&#xff0c;spring變得越來越復雜。只需訪問https://spring.io/projects頁面&#xff0c;我們就會看到可以在我們的應用程序中使用的所有Spring項目的不同功能。如果必須啟動一個新的Spring項目&#xff0…

Silverlight中使用MIRIA進行觸屏編程

Silverlight for Windows phone7中可以使用XNA提供的功能進行觸屏編程&#xff0c;不過暫時還沒有網頁Silverlight的XNA移植。經過搜索發現MIRIA這個開源項目http://miria.codeplex.com/ 可以在Silverlight中實現Touch、Gesture的功能。 用法如下&#xff1a; 1、項目中引用MIG…

React 核心開發者 Dan Abramov 訪談實錄

大家好&#xff0c;我是若川。面試、學習源碼系列、年度總結、JS基礎系列譯者注&#xff1a;本譯文是在「在線對話 React.js 核心開發者」一個半小時直播的基礎上進行的原文翻譯&#xff0c;包括了直播中的所有問答內容&#xff0c;盡可能保留了 Dan 回答的中心語義&#xff0c…

python ev3圖形化編程軟件下載_mPython(圖形化編程軟件)

mPython是盛思技術團隊在BBC官方原版PythonEditor基礎上、拓展開發的應用軟件。可以進行可視化代碼編程&#xff0c;有hex、python、blockly三種代碼讀寫等功能。功能介紹1、不依賴網絡&#xff0c;可離線安裝使用2、支持hex、python、blockly三種代碼的讀寫3、blockly模式下支…

02-15 GUCCI 我喜歡的

我覺得&#xff0c;GUCCI是低調的奢華&#xff0c;價格不是很高&#xff0c;容易接近&#xff0c;符合我的風格&#xff0c;是現階段我的選擇 樣式我喜歡 希望我的生活質量步步高升&#xff0c;將來不再為追求物質生活而奮斗。 轉載于:https://www.cnblogs.com/yd1227/archive/…

php 批量修改mysql 數據表,字段 字符集編碼

$sql"SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA 數據庫名稱";$r$pdo->query($sql,2);foreach($r as $v){//if($v[TABLE_NAME]!monxin_index_user){continue;} 代碼來源 夢行云軟件$sql"alter table ".$v[TABLE_NAME]." conver…

python如何安裝panda數據庫_在Pycharm中安裝Pandas庫方法(簡單易懂)

開發環境的搭建是一件入門比較頭疼的事情&#xff0c;在上期的文稿基礎上&#xff0c;增加一項Anaconda的安裝介紹。Anaconda是Python的一個發行版本&#xff0c;安裝好了Anaconda就相當于安裝好了Python&#xff0c;并且里面還集成了很多Python科學計算的第三方庫。比如我們需…

譯文 | Vue 在哪些方面做的比 React 更好?

大家好&#xff0c;我是若川。在過去的五年中&#xff0c;我一直是一名 React 工程師。我愛React。我喜歡開發 React 應用程序。我認為它是目前最好的UI框架之一。但是&#xff0c;在這個領域有一些競爭對手。其中最大的是 Vue.js 。我以前玩過一些 Vue.js&#xff0c;但我認為…

表單提交中Get和Post方式的區別及EncType表明提交數據的格式詳解

表單提交中Get和Post方式的區別1. get是從服務器上獲取數據&#xff0c;post是向服務器傳送數據。2. get是把參數數據隊列加到提交表單的ACTION屬性所指的URL中&#xff0c;值和表單內各個字段一一對應&#xff0c;在URL中可以看到。post是通過HTTP post機制&#xff0c;將表單…

web mp4第一幀_Web成幀器就在這里!

web mp4第一幀The Framer Team is pulling up it’s pants. I sniffed something cooking when they announced a public beta for Framer for web… FRAMER FOR WEB? Yes, I don’t know how they did it, but their powerful set of tools, plugins and animation controls …