提升前端開發質量的十點經驗沉淀
分享一下平常開發經常出現問題,增加代碼質量的十個小點:
記得錯誤處理
特別是網絡請求或者其他異步操作中,await? 記得包裹 try catch?,可以給用戶一個友好提示,同時可以考慮 catch 中需要做什么兜底處理,必要時進行上傳日志。
try {
this.loading = this.$loading({
lock: true,
text: '加載中...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)',
});
const info = await resDistributeService({ taskTicketId: this.id });
...
} catch (e) {
this.$message({
type: 'error',
message: e.msg || e.message || '失敗',
});
} finally {
this.loading.close();
}
可以結合 finally?,處理 loading 等。
數字 0 的校驗
前端經常使用 !v? ,來判斷 v 是不是有值。
if(!v){
return
}
doSomething()
但如果 0? 是 v? 的有效值 ,此時本該處理,但會提前結束,最終引發錯誤。此時需要顯示的判斷是否是 null? 或者 undefined 。
if(v === null || v=== undefined){
return
}
doSomething()
默認對象采用函數返回
由于 js 中的對象是引用,因此賦默認值的時候最好通過函數,每次都返回一個新對象。
bad:
const defaultCondition = {
name: '',
conditionList: [
{
conditionCode: '',
conditionValue: null,
},
],
}
export default {
data() {
return {
condition: {...defaultCondition},
};
},
methods: {
closeDialog() {
this.condition = {...defaultCondition};
this.configId = null;
this.$refs.form.resetFields();
},
},
};
good:
const getDefaultCondition = () => ({
name: '',
conditionList: [
{
conditionCode: '',
conditionValue: null,
},
],
})
export default {
data() {
return {
condition: getDefaultCondition(),
};
},
methods: {
closeDialog() {
this.condition = getDefaultCondition();
this.configId = null;
this.$refs.form.resetFields();
},
},
};
接口地址單獨存放
將接口的定義放到統一文件中,未來變動改動起來會比較方便,如果各個 url 都寫死在頁面中以后就很麻煩了。
// service.js
import request from 'utils/request';
const service = new (request('/api/m/mallorder/exp/compensation/customer'))();
export const listService = (params) => {
return service.post('/queryRuleList', params);
};
export const listDataKey = 'ruleVOList';
export const idKey = 'ruleId';
export const dialogEnumService = () => {
return service.get('/info');
};
export const saveService = (params) => {
return service.post('/saveRule', params);
};
export const detailService = (params) => {
return service.get('/detail', params);
};
此外,網絡請求一般都會在 npm 包的基礎上自己再包一層,一方面可以注入共用參數,另一方面可以對返回數據進行統一的錯誤處理。
函數多參數采用對象
如果定義一個函數需要 3 個以上的參數
function(a,b,c,d){
}
此時可以考慮采用對象解構,改為
function({a=1,b,c,d}={}){
}
好處是未來需要擴展參數的時候,不需要太擔心其他地方調用時候傳參是否會引起問題。
當然,如果參數過多也需要思考一下當前函數是否承載了太多的功能,進行一下功能上的拆分。
函數單一職責
當我們已經定義了一個函數,比如去初始一些變量。
function initOptions(){
a = xxx
b = xxx
}
此時我們需要做另一件無關的事 【A】,雖然它和 initOptions? 調用的時機一致,但最好不要直接放到 initOptions 中,而是新建一個函數單獨調用。
不然未來如果其他地方也要調 initOptions?,但此時可能并不需要做【A】這件事情就會引起 bug。
參數合法性判斷
由于 js 語言的靈活性,函數傳入的參數很可能不符合預期,必要時我們需要進行判斷并且進行兜底處理,不可完全信任調用方。
團隊合作中,該函數在未來極大可能會被其他人調用。
function doSomeThing(params1, params2) {
if(params1 === null){
return;
}
if(params2){
...
}
// 再去做我們的事情
}
如果后邊的流程強依賴于 params?,我們可以直接 return?,必要時也可以上報日志或者 throw Error。
整數的處理
js? 中沒有整數類型,即 java? 中的 int、long? 這些,所有數字都遵循 IEEE 754? 標準,即 java? 中的 double? 類型,詳細的可參考 浮點數詳解。
可以精確表示的最大整數是 9007199254740991?,共 16 位,超過這個數精度可能會丟失,對于新接口,可以問一下后端相應數字字段的最大值會是多少。
對于浮點數的處理,除了眾所周知的 0.1 + 0.2 === 0.3? 的值為 false 外,當我們對數字進行運算的時候也需要注意。
常見的將 9.04? 元轉為 904 分:
我們需要對結果進行取整處理。
可選鏈
可選鏈操作符,參考 MDN ,用的比較多。
和后端定的數組或者對象,后端有時候返回來的很可能是 null 甚至沒有該字段,因此前端可以用可選鏈操作符用于數組、對象、函數,防止出現錯誤直接阻斷后續流程。
let nestedProp = obj.first?.second; // 等效于 obj.first && obj.fisrt.second
//后續流程
但不要過度使用可選鏈,如果某些地方理論上不會出問題,比如 let test = obj.first?.second?,如果 second? 一定能取到,我們直接 let test = obj.first.second 即可。
不然未來如果這里由于某種原因出了問題導致 obj.first? 是 null?,但我們使用了可選鏈,所以 obj.first?.second 也不會報錯,我們就永遠不會知道這里出現問題了。
當然也需要權衡下,不加可選鏈造成 js Error 會不會影響業務邏輯。
對象or數組引用
修改或者使用對象、數組時,時刻切記它們為引用,一處修改會造成處處修改。