說明:含義不清晰,不能作到「望文生義」html
BadCode前端
var l = data.length;
GoodCodevue
// 閉包只有一行代碼,可使用單字變量 data.map(d => d.length)
說明:含義不清晰,不能作到「望文生義」react
BadCodeios
var obj = {}; var obj2 = {...obj, key: 1};
GoodCodegit
var obj = {}; var objWithKey = {...obj, key: 1};
此處動詞沒有包含時態
變量名應該是名詞或者名詞短語。github
例外:redux
說明:canvas
BadCodeaxios
// 以名詞開頭,看不明白什麼有什麼功能 function option() {} // 時態不對 function updatedTime() {}
GoodCode
function selectOption() {} function updateTime() {}
例外:
說明:含義不清晰,不能作到「望文生義」
BadCode
var uo = function updateOrder(){} var as = [].slice; var ex = Object.extends; var nu = number
GoodCode
// weixin/wx 是專有名詞 var weixinUser = {}; var wx = weixin; // POI 是專有名詞 var poi = {};
例外:專有 API,如 alert
說明:在上層做用域下的代碼,會被更多函數使用到。其名稱應該儘可能長或者通用,以保證可以搜索到。
BadCode
// 在全局變量上定義了一個 item 變量,可是很難從命名上理解其做用是什麼。 window.item = {}
GoodCode
window.primaryProductItem = {};
說明:變量中加符號,每每是爲了約定其優先級或者做用域。符號應該在變量名前面。
BadCode
function getDot_(){} function privateFn$$ (){}
GoodCode
function _getDot() {} function $$privateFn() {}
說明:類做爲實例的所屬,其名稱表達的含義要一脈相承
BadCode
class Person() {} var dog = new Person(); // dog is a Person ?
GoodCode
class Person() {} var jack = new Person();
說明:粗暴的翻譯,更容易形成誤解,還不如寫拼音
BadCode
// 渲染「頁面頂部的執行人」 // 仍是渲染「執行砍頭的人」? function renderHeadExecutantPeople(){}
GoodCode
function renderHeader() {}
說明:避免通一個概念在不一樣的代碼用多種不一樣的單詞描述。
BadCode
// 遠程請求這個概念,前後用了 get/fetch/query // 三個名詞去描述 function getUserInfo() {} function fetchProductInfo() {} function queryPayment() {}
GoodCode
// 統一用 get 描述 // 閱讀代碼的人能體會到其中的共性 function getUserInfo() {} function getProductInfo() {} function getPayment() {}
例外:專有詞
說明:雙關語容易引發歧義
BadCode
// 訂單類型,仍是排序類型? var orderType
GoodCode
var sortType
說明:命名每每是實現的隱喻,若是存在差別則會讓閱讀者看不懂代碼。
BadCode
// empty 的命名含義和實現截然相反 // (我真的見過這種代碼) function getProduct(id) { axios.delete('/product', {id}); }
GoodCode
function deleteProduct(id) { axios.delete('/product', {id}); }
說明:布爾變量的名稱中,若是加上 「not」之類的否認詞,則至關於作了一次了邏輯判斷。
BadCode
const notEmpty = !!array.length;
GoodCode
const empty = !array.length;
說明:代碼太長說明作的事情不夠專注,同時也會讓閱讀變得很困難。
說明:一樣功能的代碼不要重複三次
說明:代碼裏的邏輯分支要儘可能少,只作一件事情,而且要處理好邊界和異常狀況。
說明:函數的輸入越多,每每就表明功能約複雜
說明:對於比較奇怪的業務邏輯,或者由於系統、接口緣由而寫的比較奇怪的邏輯。要經過註釋標註出來
BadCode
framework.doSomeThing(); framework.reset(); // 閱讀者心裏 OS:這裏爲啥要作一次 reset? framework.continueSomeThing();
GoodCode
framework.doSomeThing(); // framework 有個 bug,這裏必需要作一次 rest 附連接: http://github.com/issuse/*** framework.reset(); framework.continueSomeThing();
說明:純函數比較好測試,邏輯也比較清晰,能夠放心的引入和刪除。
BadCode
let status; function method() { if (status) { ... } }
GoodCode
function method(status) { if (status) { ... } }
說明:修改參數會致使函數的做用變得不可預測
BadCode
function updateObj(obj, value) { obj.key = value; return obj; }
GoodCode
function updateObj(obj, value) { return {...obj, key: value}; }
說明:this 的指向常常不固定,會致使代碼難以理解。若是調用方不熟悉的話,很容易引發 Bug。
BadCode
function method() { console.log(this.value); } method() // 報錯 var obj = { method, value: 1} obj.method() // 輸出 1
GoodCode
function method(value) { console.log(value); }
說明:錯誤也是一種邏輯分支,若是不處理的話,代碼就不夠健壯。前端代碼處理錯誤的方式通常爲提示用戶有異常發生。若是錯誤不影響業務流程,則寫入日誌裏並上報。
BadCode
function method(data) { try { return JSON.parse(data) } catch (e) {} }
GoodCode
function method(data) { try { return JSON.parse(data) } catch (e) { alert('數據處理失敗') } }
說明:magic number 是指直接在代碼中硬編碼的數字,每每具備一些業務含義。
這樣會致使:
BadCode
if (status === 1) { ... } else if (type === 4) { ... }
GoodCode
enum Status { Closed } enum Type { Array } if (status === Status.Closed) { ... } else if (type === Type.Array) { ... }
說明:原子性意味着獨立,且不可分割。其它屬性都由原子業務屬性推導、計算而來,這樣能保證狀態的一致。
BadCode
// 當 status 爲 open 的時候展現彈窗 // 其它狀態則隱藏彈窗 { data() { return { showAlert: false, status: 'closed', } }, onStatusChange() { if (status === 'open') { this.showAlert = true; } else { this.showAlert = false; } } }
GoodCode
// showAlert 爲非原子的狀態 // 其狀態能夠由 status 推導而來 { data() { return { status: 'closed', } }, computed: { showAlert() { return this.status === 'open'; } } }
說明:
BadCode
// 在一個列表中,用戶能夠對數據作多選 // 而後刪除他們 class extends React.Component { async componentDidMount() { const listData = getData(); this.setState({ listData }) } check = (item) => { const listData = this.state.listData.map(i => { if (i === item) { return {...item, checked: true} } return i; }); this.setState({ listData }); } delete() { // 返回給後端的數據結構,會多出一個 checked 字段 deleteItems(this.state.listData.filter(i => i.checked)); } render() { const list = this.state.listData.map(item => { const className = ['item']; if (item.checked) className.push('active'); return <label className={className} onClick={() => this.check(item)} >{item.naem}</label>; }); return <> {list} <button onClick={this.delete}>delete</button> </> } }
GoodCode
// 在一個列表中,用戶能夠對數據作多選 // 而後刪除他們 class extends React.Component { async componentDidMount() { const listData = getData(); // 使用獨立的 selected 來保存 UI 狀態 this.setState({ listData, selected: [] }) } check = (item) => { let { selected } = this.state; selected = selected.findOrInsert(s => s.id, item); this.setState({ selected }); } delete() { const { selected, listData } = this.state; deleteItems(listData.filter(i => selected.includes(i.id)))); } render() { const { selected, listData } = this.state; const list = listData.map(item => { const className = ['item']; if (selected.includes(item.id)) className.push('active'); return <label className={className} onClick={() => this.check(item)} >{item.naem}</label>; }); return <> {list} <button onClick={this.delete}>delete</button> </> } }
說明:react 的 render 應該是純函數,在 render 裏運行 setState 會致使重複渲染,或者死循環。
BadCode
// 若是 type 爲 http 的話,則自動轉換爲 https class extends React.Component { render() { const { type } = this.state; if (type === 'http') { this.setState({ type: 'https'}) } return <label>{type}</label>; } }
GoodCode
// 若是 type 爲 http 的話,則自動轉換爲 https class extends React.Component { get type() { const { type } = this.state; if (type === 'http') return 'https'; return type; } render() { const type = this.type; return <label>{type}</label>; } }
說明:
BadCode
// foo 和 bar 互相依賴,致使了死循環 { data() { return { foo: 1, }; }, computed: { bar() { return this.foo + 1; } }, watch() { bar() { this.foo = this.bar + 1; }, } }
說明:好比用雙等號作判斷
BadCode
const foo = '0'; const bar = 0 // 作數據判斷時不能用雙等號 foo == bar // true foo ? 1 : 2 // 1 bar ? 1 : 2 // 2 // 僅經過變量有沒有 length 來判斷是否爲數組 if(obj.length) { obj.forEach(...) }
GoodCode
const foo = '0'; const bar = 0 foo === bar // false if (Array.isArray(obj)) { obj.forEach(...) }
說明:這樣作會致使數據的異常。若是須要作這種操做,最好使用數組函數,或者操做拷貝數據。
BadCode
const array = [1,2,3,4,5,6,7,8,9,10]; // 刪除數組中的偶數 for (var i = 0; i < array.length; i++) { if (array[i] % 2 == 0) array.splice(i); } // array 變成了 [1]
GoodCode
const array = [1,2,3,4,5,6,7,8,9,10]; array.filter(a => !(a % 2))
說明:
大多數場景下,setTimeout 後面傳遞一個時間是爲了先執行後續的 A 代碼,再延後執行代碼閉包裏的 B 代碼,如右邊示例代碼。
但若是隨着業務迭代,A 被改爲異步,或者執行時間很長的話。以前作的延遲執行的防護措施就時效了,也許反而 B 會比 A 先執行。
BadCode
// 代碼的原本意圖是讓 B 延後執行 setTimeout(() => { B(); }, 1000); A(); // 代碼的意圖是讓 render 在下一幀執行 // 可是不一樣設備,一幀時間是不固定的 setTimeout(() => { render() }, 16);
GoodCode
// A 函數內要想辦法使用 Promise 串接起來 await A(); b(); // 使用系統提供的 API 執行動畫幀 requestAnimationFrame(() => { render(); });
說明:陳舊的 API 每每有不少問題,好比安全、性能、不易讀等。
BadCode
// 判斷是否爲數組 Object.prototype.toString.call(array) === "[object Array]" // 查找數組裏第一個偶數 for (var i = 0; i < array.length; i++) { if (array[i] % 2 === 0) return array[i]; } // 遍歷對象的 key for (var key in obj) { console.log(key); } // 判斷字符串/數組是否包含 'some text'.indexOf('some') >= 0 // 去除首位空格 ' some text '.replace(/(^\s+|\s+$)/g, '') // 新建對象/數組 const array = new Array(); const obj = new Object();
GoodCode
Array.isArray(array) array.find(a => a % 2 === 0); Object.keys(obj).forEach(console.log) 'some text'.includes('some') ' some text '.trim() const array = []; const obj = {};
說明:
React Ref 通常是用來處理和原生 DOM 交互的場景,好比 canvas。
大部分對於 React ref 的使用都是錯誤的,大多都拿來用來控制子元素。這種場景咱們更推薦用數據流(redux,mobx)或者用狀態提高去作。
React 官方有對「狀態提高」的描述 https://react.docschina.org/d...
BadCode
class List extends React.Component { async refresh() { this.setState({ items: getItems(), }); } render() { return this.state.items.map(i => <label>{i}</label>); } } class extends React.Component { onRefresh = () => { // 用 ref 去調用子元素的方法 this.list.refresh(); } render() { return <> <List ref={l => this.list = l}></List> <button onClick={this.onRefresh}/> </>; } }
GoodCode
class List extends React.Component { render() { return this.props.items.map(i => <label>{i}</label>); } } class extends React.Component { // 把數據狀態提高到父組件作操做 refresh = async () => { this.setState({ items: getItems(), }); } render() { return <> <List items{this.state.items}></List> <button onClick={this.refresh}/> </>; } }
說明:
字符串拼接 url 須要處理 encode 或者 decode 的狀況,還有對於 ?和 # 的判斷不對的話,很容易形成漏洞或者 Bug。
目前瀏覽器和 Node 都已經提供了標準的 URL 解析方法。
https://developer.mozilla.org...
BadCode
// 這段代碼既沒有對 key、value 作 encode // 也沒有考慮 url 中 # 出現的狀況 const url = location.href; if (url.indexOf('?') >= 0) { return url + key + '=' + value; } else { return url + '?' + key + '=' + value; }
GoodCode
// 使用標準的 URL 解析,風險會下降不少 const url = new URL(urlStr); url.searchParams.set(key, value); return url.toString();
說明:
咱們應該指望 if 條件內是個「真」值,而不是一個「假」值。
第二種狀況會致使代碼不易理解。
解決辦法參考 布爾邏輯
BadCode
// if 條件內指望的是一個「假」值 if (!(status !== Closed) { ... } if (!(status !== Closed || type !== Array)) { ...}
GoodCode
if (status === Closed) { ... } if (status === Closed && type === Array) { ... }
例外:if 條件裏能夠被 「且」(&&)邏輯拆分紅多個子條件
說明:複雜的條件判斷會讓代碼不易理解,邏輯上有漏洞的話容易引發 Bug。
解決辦法:聲明中間變量
BadCode
if (srcElem != dropElem && (srcElem.nextSibling || srcElem.nextElementSibling) != dropElem) {...} if (selectedItem || (selectedEmployee && selectedEmployee.empId && selectedEmployee) || employee) { ... }
GoodCode
const nextSibling = srcElem.nextSibling || srcElem.nextElementSibling if (srcElem != dropElem && nextSibling != dropElem ) { ... } // 複雜的邏輯判斷能夠經過 && 作拆分 if ( !Array.isArray(cur) && cur != null && typeof src[key] === 'object' && typeof cur === 'object' ) { ... }
說明:
人們閱讀嵌套三元表達式時,容易混淆語法的優先級,進而致使理解錯代碼的含義。
對於這種狀況,建議改爲 if else。
若是是在 react render 裏,則建議獨立成函數。
BadCode
function render(props) { const value = props.value; return <> {value < 10 ? value > 0 ? value : 200 - value : 100 - value} </>; }
GoodCode
function getValue(value) { if (value < 10) { if (value > 0) return value; return 200 - value; } return 100 - value; } function render(props) { const value = props.value; return <> {getValue(value)} </>; }
說明:過深的嵌套會致使理解困難。
解決辦法:合併判斷條件,或者獨立成函數。
BadCode
if (status = Opened) { if (type = 'array') { if (code = Success) { doSomething(); } } }
GoodCode
if (status = Opened && type = 'array' &&code = Success) { doSomething(); }