[譯] 我們能從 Redux 原始碼中學到什麼?

繆宇發表於2018-03-22

我們能從 Redux 原始碼中學到什麼?

[譯] 我們能從 Redux 原始碼中學到什麼?

我總是聽人說,想擴充開發者自身視野就去讀原始碼吧。

所以我決定找一個高質量的 JavaScript 庫來深入學習。

我選擇了 Redux,因為它的程式碼比較少。

這篇文章不是 Redux 教程,而是閱讀原始碼後的收穫。如果你對學習 Redux 感興趣,強烈推薦你去看 Redux 教程,這個系列文章是 Redux 的作者 Dan Abramov 寫的。

從原始碼中學習

一些新來的開發者經常問我,怎樣才是最好的學習方式?我往往會告訴他們在專案中學習。

當你構建一個專案來實踐你的想法時,由於你對它的熱愛,會讓你度過難熬的 debug 階段,即使遇到困難也不會放棄。這是一個非常神奇的現象。

但是一個人閉門造車也是有問題的。你不會注意到你開發過程中的壞習慣,你也學不到任何最優的解決方案。你可能都不知道又出了哪些新的框架和技術。在獨自寫專案的過程中,你很快會發現你的技能達到瓶頸。

只要有可能,我建議你找些小夥伴和你一起開發。

試想一下,坐在你旁邊的小夥伴(如果你夠幸運,他恰好是個大神),你可以觀察他思考問題的過程。你可以看他是如何敲程式碼的。你可以看他是如何解決演算法問題的。你可以學到新的開發工具和快捷鍵。你會學到許多你一個人開發時學不到的東西。

[譯] 我們能從 Redux 原始碼中學到什麼?

斯特拉迪瓦里小提琴。

我用斯特拉迪瓦里的小提琴舉個例子。斯特拉迪瓦里小提琴以出色的音質聞名世界,在業界可以說是一枝獨秀。許多人嘗試用各種方法去解釋為什麼它這麼牛逼,從古老教堂搶救出來的木材到特殊的木材的防腐劑。許多人想要複製一把斯特拉迪瓦里小提琴,結果都失敗了,因為他們不知道安東尼·斯特拉迪瓦里到底是怎麼做的。

設想一下,如果你和安東尼·斯特拉迪瓦里在一個房間裡工作,那麼所有的獨門祕籍你都可以學到。

這下你知道該如何與你的開發小夥伴相處了吧。你只需要安靜的坐他旁邊,看著他寫出一行行斯特拉迪瓦里式的程式碼。

對於與多人來說,協同程式設計是一個很好的機會,可以通過別人的程式碼學到很多東西。

閱讀高質量的程式碼就像讀一本精彩的小說一樣,比起直接和作者交流,你可能理解起來比較困難。但是你可以通過看註釋和程式碼,獲取到有價值的資訊。

對於那些認為看原始碼沒什麼用的的同學,你可以去看一個故事,一個叫比爾·蓋茨的高中生,為了瞭解某個公司的機密,他甚至去翻人家的垃圾桶找原始碼。

如果你也可以像比爾·蓋茨那樣不厭其煩的看原始碼,那還在等什麼?找一個 github 倉庫,看原始碼吧!

[譯] 我們能從 Redux 原始碼中學到什麼?

咦,原始碼呢?

閱讀原始碼的同時,你也可以去看官方文件,官方文件的結構就像作者寫的程式碼一樣,寫得好的官方文件就讓你彷彿坐在作者旁邊一樣。你也可以在上面看到別人遇到的問題。官方文件中的超連結提供了豐富的擴充套件閱讀的資源。在評論區你還可以和大神一起交流。

平時我也會在 YouTube 看別人寫程式碼,我推薦大家去看SuperCharged 直播寫程式碼系列,來自 Google Chrome 開發者的 Youtube 頻道。看兩個 Google 工程師直播寫一個專案,看他們是如何處理效能問題的,和大家一樣,他們也會被自己拼寫錯誤導致的 bug 卡住。

讀 Readux 原始碼的收穫

ESLint

Linting 用於檢查程式碼,發現潛在的錯誤。它幫助我們保持程式碼風格的一致性和整潔。你可以自己定製規則,也可以用預設的規則(比如 Airbnb 提供的規則)。

Linting 在團隊開發中特別有用。它讓所有程式碼看起來像一個人寫的。它可以強迫開發人員按照公司的程式碼風格來寫程式碼(同事不用在閱讀程式碼上花太多時間)。

Linters 不僅僅是為了美觀,它會讓你的程式碼更符合語言特性。比如它會告訴你什麼時候使用 “const” 關鍵字來處理那些沒有被重新賦值的變數。

如果你使用了 React 外掛,它會警告你關於元件可以被重構成無狀態的函式式元件。也是可以讓你學習 ES6 語法,告訴你的某段程式碼可以用語法新特性來寫。

在你的專案中輕鬆使用 ESlint:

  1. 安裝 ESlint。
$ npm install --save-dev eslint
複製程式碼
  1. 配置 ESlint。
./node_modules/.bin/eslint --init
複製程式碼
  1. 在你的 package.json 檔案中設定 npm 指令碼來執行你的 Linter(可選)。
"scripts": {
  "lint": "./node_modules/.bin/eslint"
}
複製程式碼
  1. 執行 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,以及理清程式碼邏輯。

在控制檯中產生的錯誤,可以很方便堆疊跟蹤。

[譯] 我們能從 Redux 原始碼中學到什麼?

很有用的棧跟蹤。

做異常資訊處理讓你的程式碼邏輯清晰。比如,如果有一個 "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 的陣列的重新排列的方法

描述性的函式名

在原始碼中,我看到了許多有很長名字的函式。

  1. getUndefinedStateErrorMessage
  2. getUnexpectedStateShapeWarningMessage
  3. assertReducerSanity

雖然這函式名讀起來會讓你的舌頭打結,但你可以清楚的知道這個函式是做什麼的。

在你的程式碼中使用描述性的函式名,讓你更多的是讀程式碼而不是寫程式碼,別人也可以很輕鬆的閱讀你的程式碼。

用較長的描述性函式名帶來的好處遠超過敲擊鍵盤所帶來的快感。現代的文字編輯器都有自動補全功能,它可以幫助你輸入,所以沒有理由再使用類似 “x” 或者 “y” 的變數名。

console.error vs. console.log

不要總是使用 console.log,如果你要丟擲異常,請使用 console.error,你可以在 console 中看到紅色的列印內容和棧的跟蹤。

[譯] 我們能從 Redux 原始碼中學到什麼?

console.error()

檢視 console 文件,看看其他的方法。比如計算執行時間的計時器(console.time()),用表格方式列印資訊(console.table()),等等。


不要害怕去讀原始碼。你肯定會學到一些東西,甚至可以為它貢獻程式碼。

在評論中分享你在閱讀原始碼中的收穫吧!


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章