- 原文地址:What I learned from reading the Redux source code
- 原文作者:Anthony Ng
- 譯文出自:掘金翻譯計劃
- 本文永久連結:github.com/xitu/gold-m…
- 譯者:繆宇
- 校對者:anxsec 輕舞飛揚
我們能從 Redux 原始碼中學到什麼?
我總是聽人說,想擴充開發者自身視野就去讀原始碼吧。
所以我決定找一個高質量的 JavaScript 庫來深入學習。
我選擇了 Redux,因為它的程式碼比較少。
這篇文章不是 Redux 教程,而是閱讀原始碼後的收穫。如果你對學習 Redux 感興趣,強烈推薦你去看 Redux 教程,這個系列文章是 Redux 的作者 Dan Abramov 寫的。
從原始碼中學習
一些新來的開發者經常問我,怎樣才是最好的學習方式?我往往會告訴他們在專案中學習。
當你構建一個專案來實踐你的想法時,由於你對它的熱愛,會讓你度過難熬的 debug 階段,即使遇到困難也不會放棄。這是一個非常神奇的現象。
但是一個人閉門造車也是有問題的。你不會注意到你開發過程中的壞習慣,你也學不到任何最優的解決方案。你可能都不知道又出了哪些新的框架和技術。在獨自寫專案的過程中,你很快會發現你的技能達到瓶頸。
只要有可能,我建議你找些小夥伴和你一起開發。
試想一下,坐在你旁邊的小夥伴(如果你夠幸運,他恰好是個大神),你可以觀察他思考問題的過程。你可以看他是如何敲程式碼的。你可以看他是如何解決演算法問題的。你可以學到新的開發工具和快捷鍵。你會學到許多你一個人開發時學不到的東西。
斯特拉迪瓦里小提琴。
我用斯特拉迪瓦里的小提琴舉個例子。斯特拉迪瓦里小提琴以出色的音質聞名世界,在業界可以說是一枝獨秀。許多人嘗試用各種方法去解釋為什麼它這麼牛逼,從古老教堂搶救出來的木材到特殊的木材的防腐劑。許多人想要複製一把斯特拉迪瓦里小提琴,結果都失敗了,因為他們不知道安東尼·斯特拉迪瓦里到底是怎麼做的。
設想一下,如果你和安東尼·斯特拉迪瓦里在一個房間裡工作,那麼所有的獨門祕籍你都可以學到。
這下你知道該如何與你的開發小夥伴相處了吧。你只需要安靜的坐他旁邊,看著他寫出一行行斯特拉迪瓦里式的程式碼。
對於與多人來說,協同程式設計是一個很好的機會,可以通過別人的程式碼學到很多東西。
閱讀高質量的程式碼就像讀一本精彩的小說一樣,比起直接和作者交流,你可能理解起來比較困難。但是你可以通過看註釋和程式碼,獲取到有價值的資訊。
對於那些認為看原始碼沒什麼用的的同學,你可以去看一個故事,一個叫比爾·蓋茨的高中生,為了瞭解某個公司的機密,他甚至去翻人家的垃圾桶找原始碼。
如果你也可以像比爾·蓋茨那樣不厭其煩的看原始碼,那還在等什麼?找一個 github 倉庫,看原始碼吧!
咦,原始碼呢?
閱讀原始碼的同時,你也可以去看官方文件,官方文件的結構就像作者寫的程式碼一樣,寫得好的官方文件就讓你彷彿坐在作者旁邊一樣。你也可以在上面看到別人遇到的問題。官方文件中的超連結提供了豐富的擴充套件閱讀的資源。在評論區你還可以和大神一起交流。
平時我也會在 YouTube 看別人寫程式碼,我推薦大家去看SuperCharged 直播寫程式碼系列,來自 Google Chrome 開發者的 Youtube 頻道。看兩個 Google 工程師直播寫一個專案,看他們是如何處理效能問題的,和大家一樣,他們也會被自己拼寫錯誤導致的 bug 卡住。
讀 Readux 原始碼的收穫
ESLint
Linting 用於檢查程式碼,發現潛在的錯誤。它幫助我們保持程式碼風格的一致性和整潔。你可以自己定製規則,也可以用預設的規則(比如 Airbnb 提供的規則)。
Linting 在團隊開發中特別有用。它讓所有程式碼看起來像一個人寫的。它可以強迫開發人員按照公司的程式碼風格來寫程式碼(同事不用在閱讀程式碼上花太多時間)。
Linters 不僅僅是為了美觀,它會讓你的程式碼更符合語言特性。比如它會告訴你什麼時候使用 “const” 關鍵字來處理那些沒有被重新賦值的變數。
如果你使用了 React 外掛,它會警告你關於元件可以被重構成無狀態的函式式元件。也是可以讓你學習 ES6 語法,告訴你的某段程式碼可以用語法新特性來寫。
在你的專案中輕鬆使用 ESlint:
- 安裝 ESlint。
$ npm install --save-dev eslint
複製程式碼
- 配置 ESlint。
./node_modules/.bin/eslint --init
複製程式碼
- 在你的 package.json 檔案中設定 npm 指令碼來執行你的 Linter(可選)。
"scripts": {
"lint": "./node_modules/.bin/eslint"
}
複製程式碼
- 執行 Linter.
$ npm run lint
複製程式碼
檢視它們的官方文件,瞭解更多。
許多編輯器也有外掛來檢查你的程式碼。
有些時候 Linter 會對一些正確的程式碼報錯,比如 console.log。你可以告訴 Linter 忽略這行程式碼,不對其進行檢查。
在 ESlint 中忽略檢查,你可以這樣寫程式碼註釋:
// 忽略一行
console.log(‘Hello World’); // eslint-disable-line no-console
// 忽略多行
/* eslint-disable no-console */
console.log(‘Hello World’);
console.log(‘Goodbye World’);
/* eslint-enable no-console */
複製程式碼
檢查程式碼是否被壓縮了
在原始碼中我發現一個 “isCrushed()” 的空函式,很奇怪。
後來我發現它的目的是為了檢查程式碼是否被壓縮了。在程式碼壓縮過程中,函式名字和變數會被縮寫。當你在開發的時候如果使用了壓縮後的程式碼,如果一個條語句被檢測到仍然有 “isCrushed()” 存在,就會有警告提示。
不要害怕報錯
在學習 Redux 原始碼之前我很少在程式碼中拋異常。JavaScript 是一個弱型別,所以我們不知道函式中傳入引數的型別。所以我們必須要像強型別語言那樣對於錯誤要丟擲異常。
使用 try…catch…finally
語句來丟擲異常。這樣做可以方便你 debug,以及理清程式碼邏輯。
在控制檯中產生的錯誤,可以很方便堆疊跟蹤。
很有用的棧跟蹤。
做異常資訊處理讓你的程式碼邏輯清晰。比如,如果有一個 "add()" 函式,只允許傳入數字,如果傳入的不是數字就要丟擲異常。
function add(a, b) {
if(typeof a !== ‘number’ || typeof b !== ‘number’) {
throw new Error(‘Invalid arguments passed. Expected numbers’);
}
return a + b;
}
var sum = add(‘foo’, 2);
// 丟擲異常後會終止程式碼執行
複製程式碼
組合函式
原始碼中有一個 “compose()” 函式,根據已有的函式構建出新的函式:
function compose(…funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
const last = funcs[funcs.length — 1]
const rest = funcs.slice(0, -1)
return (…args) => rest.reduceRight((composed, f) => f(composed), last(…args))
}
複製程式碼
如果我有兩個已知的 square 函式和另一個 double 函式,我可以把它們組成一個新函式。
function square(num) {
return num * num;
}
function double(num) {
return num * 2;
}
function squareThenDouble(num) {
return compose(double, square)(num);
}
console.log(squareThenDouble(7)); // 98
複製程式碼
如果我沒看過 Redux 的原始碼,我都不知道還有這種犀利的操作。
原生方法
當我在看 “compose” 函式的時候,我發現了一個原生陣列方法 “reduceRight()”,我之前都沒聽到過。這讓我想知道還有多少我沒聽過的原生方法。
我們來看一個程式碼片段,一個使用了原生陣列方法 “filter()”,一個沒有,通過對比看原生方法存在的價值。
function custom(array) {
let newArray = [];
for(var i = 0; i < array.length; i++) {
if(array[i]) {
newArray.push(array[i]);
}
}
return newArray;
}
function native(array) {
return array.filter((current) => current);
}
const myArray = [false, true, true, false, false];
console.log(custom(myArray));
console.log(native(myArray));
複製程式碼
你可以看到使用 “filter()” 會讓你的程式碼變得簡潔。更重要的是,避免了重複造輪子。“filter()” 會被使用上百萬次,比起你自己造輪子,可以避免很多 bug。
當你想造輪子的時候,先看看你的問題是否已經被原生方法解決了。你會驚喜的發現有非常多的實用方法在你用的程式語言中。(比如,可以看看 Ruby 的陣列的重新排列的方法)
描述性的函式名
在原始碼中,我看到了許多有很長名字的函式。
- getUndefinedStateErrorMessage
- getUnexpectedStateShapeWarningMessage
- assertReducerSanity
雖然這函式名讀起來會讓你的舌頭打結,但你可以清楚的知道這個函式是做什麼的。
在你的程式碼中使用描述性的函式名,讓你更多的是讀程式碼而不是寫程式碼,別人也可以很輕鬆的閱讀你的程式碼。
用較長的描述性函式名帶來的好處遠超過敲擊鍵盤所帶來的快感。現代的文字編輯器都有自動補全功能,它可以幫助你輸入,所以沒有理由再使用類似 “x” 或者 “y” 的變數名。
console.error vs. console.log
不要總是使用 console.log,如果你要丟擲異常,請使用 console.error,你可以在 console 中看到紅色的列印內容和棧的跟蹤。
console.error()
檢視 console 文件,看看其他的方法。比如計算執行時間的計時器(console.time()),用表格方式列印資訊(console.table()),等等。
不要害怕去讀原始碼。你肯定會學到一些東西,甚至可以為它貢獻程式碼。
在評論中分享你在閱讀原始碼中的收穫吧!
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。