測試代碼質量的唯一方式:別人看你代碼時說 f * k 的次數。
代碼質量與其整潔度成正比。乾淨的代碼,既在質量上較為可靠,也為後期維護、升級奠定了良好基礎。
本文並不是代碼風格指南,而是關於代碼的可讀性、複用性、擴展性探討。
我們將從幾個方面展開討論:
- 變量
- 函數
- 對象和數據結構
- 類
- SOLID
- 測試
- 異步
- 錯誤處理
- 代碼風格
- 註釋
變量
用有意義且常用的單詞命名變量
保持統一
可能同一個項目對於獲取用戶信息,會有三個不一樣的命名。應該保持統一,如果你不知道該如何取名,可以去 codelf (https://unbug.github.io/codelf/) 搜索,看別人是怎麼取名的。
每個常量都該命名
可以用 buddy.js 或者 ESLint 檢測代碼中未命名的常量。
可描述
通過一個變量生成了一個新變量,也需要為這個新變量命名,也就是說每個變量當你看到他第一眼你就知道他是幹什麼的。
直接了當
避免無意義的前綴
如果創建了一個對象 car,就沒有必要把它的顏色命名為 carColor。
使用默認值
函數
參數越少越好
如果參數超過兩個,使用 ES2015/ES6 的解構語法,不用考慮參數的順序。
只做一件事情
這是一條在軟件工程領域流傳久遠的規則。嚴格遵守這條規則會讓你的代碼可讀性更好,也更容易重構。如果違反這個規則,那麼代碼會很難被測試或者重用。
顧名思義
看函數名就應該知道它是幹啥的。
對象設置默認屬性
不要傳 flag 參數
通過 flag 的 true 或 false,來判斷執行邏輯,違反了一個函數幹一件事的原則。
避免副作用(第一部分)
函數接收一個值返回一個新值,除此之外的行為我們都稱之為副作用,比如修改全局變量、對文件進行 IO 操作等。
當函數確實需要副作用時,比如對文件進行 IO 操作時,請不要用多個函數/類進行文件操作,有且僅用一個函數/類來處理。也就是說副作用需要在唯一的地方處理。
副作用的三大天坑:隨意修改可變數據類型、隨意分享沒有數據結構的狀態、沒有在統一地方處理副作用。
避免副作用(第二部分)
在 JavaScript 中,基本類型通過賦值傳遞,對象和數組通過引用傳遞。以引用傳遞為例:
假如我們寫一個購物車,通過 addItemToCart() 方法添加商品到購物車,修改 購物車數組。此時調用 purchase() 方法購買,由於引用傳遞,獲取的 購物車數組 正好是最新的數據。
看起來沒問題對不對?
如果當用戶點擊購買時,網絡出現故障, purchase() 方法一直在重複調用,與此同時用戶又添加了新的商品,這時網絡又恢復了。那麼 purchase() 方法獲取到 購物車數組 就是錯誤的。
為了避免這種問題,我們需要在每次新增商品時,克隆 購物車數組 並返回新的數組。
不要寫全局方法
在 JavaScript 中,永遠不要汙染全局,會在生產環境中產生難以預料的 bug。舉個例子,比如你在 Array.prototype 上新增一個 diff 方法來判斷兩個數組的不同。而你同事也打算做類似的事情,不過他的 diff 方法是用來判斷兩個數組首位元素的不同。很明顯你們方法會產生衝突,遇到這類問題我們可以用 ES2015/ES6 的語法來對 Array 進行擴展。
比起命令式我更喜歡函數式編程
函數式變編程可以讓代碼的邏輯更清晰更優雅,方便測試。
封裝條件語句
儘量別用“非”條件句
避免使用條件語句
Q:不用條件語句寫代碼是不可能的。
A:絕大多數場景可以用多態替代。
Q:用多態可行,但為什麼就不能用條件語句了呢?
A:為了讓代碼更簡潔易讀,如果你的函數中出現了條件判斷,那麼說明你的函數不止幹了一件事情,違反了函數單一原則。
避免類型檢查(第一部分)
JavaScript 是無類型的,意味著你可以傳任意類型參數,這種自由度很容易讓人困擾,不自覺的就會去檢查類型。仔細想想是你真的需要檢查類型還是你的 API 設計有問題?
避免類型檢查(第二部分)
如果你需要做靜態類型檢查,比如字符串、整數等,推薦使用 TypeScript,不然你的代碼會變得又臭又長。
不要過度優化
現代瀏覽器已經在底層做了很多優化,過去的很多優化方案都是無效的,會浪費你的時間,想知道現代瀏覽器優化了哪些內容,請點這裡。
刪除棄用代碼
很多時候有些代碼已經沒有用了,但擔心以後會用,捨不得刪。
如果你忘了這件事,這些代碼就永遠存在那裡了。
放心刪吧,你可以在代碼庫歷史版本中找他它。
對象和數據結構
用 get、set 方法操作數據
這樣做可以帶來很多好處,比如在操作數據時打日誌,方便跟蹤錯誤;在 set 的時候很容易對數據進行校驗...
使用私有變量
可以用閉包來創建私有變量
類
使用 class
在 ES2015/ES6 之前,沒有類的語法,只能用構造函數的方式模擬類,可讀性非常差。
鏈式調用
這種模式相當有用,可以在很多庫中發現它的身影,比如 jQuery、Lodash 等。它讓你的代碼簡潔優雅。實現起來也非常簡單,在類的方法最後返回 this 可以了。
不要濫用繼承
很多時候繼承被濫用,導致可讀性很差,要搞清楚兩個類之間的關係,繼承表達的一個屬於關係,而不是包含關係,比如 Human->Animal vs. User->UserDetails
SOLID
SOLID 是幾個單詞首字母組合而來,分別表示 單一功能原則、開閉原則、里氏替換原則、接口隔離原則以及依賴反轉原則。
單一功能原則
如果一個類乾的事情太多太雜,會導致後期很難維護。我們應該釐清職責,各司其職減少相互之間依賴。
測試
隨著項目變得越來越龐大,時間線拉長,有的老代碼可能半年都沒碰過,如果此時上線,你有信心這部分代碼能正常工作嗎?測試的覆蓋率和你的信心是成正比的。
PS: 如果你發現你的代碼很難被測試,那麼你應該優化你的代碼了。
單一化
異步
不再使用回調
不會有人願意去看嵌套回調的代碼,用 Promises 替代回調吧。
Async/Await 比起 Promises 更簡潔
錯誤處理
不要忽略拋異常
不要忘了在 Promises 拋異常
代碼風格
代碼風格是主觀的,爭論哪種好哪種不好是在浪費生命。市面上有很多自動處理代碼風格的工具,選一個喜歡就行了,我們來討論幾個非自動處理的部分。
常量大寫
註釋
只有業務邏輯需要註釋
代碼註釋不是越多越好。
刪掉註釋的代碼
git 存在的意義就是保存你的舊代碼,所以註釋的代碼趕緊刪掉吧。
不要記日記
記住你有 git!,git log 可以幫你幹這事。
註釋不需要高亮
註釋高亮,並不能起到提示的作用,反而會干擾你閱讀代碼。
作者 : 繆宇
閱讀更多 前端學習指南 的文章