提升前端開發(fā)質(zhì)量的十點經(jīng)驗沉淀
分享一下平常開發(fā)經(jīng)常出現(xiàn)問題,增加代碼質(zhì)量的十個小點:
記得錯誤處理
特別是網(wǎng)絡(luò)請求或者其他異步操作中,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();
}
可以結(jié)合 finally?,處理 loading 等。
數(shù)字 0 的校驗
前端經(jīng)常使用 !v? ,來判斷 v 是不是有值。
if(!v){
return
}
doSomething()
但如果 0? 是 v? 的有效值 ,此時本該處理,但會提前結(jié)束,最終引發(fā)錯誤。此時需要顯示的判斷是否是 null? 或者 undefined 。
if(v === null || v=== undefined){
return
}
doSomething()
默認對象采用函數(shù)返回
由于 js 中的對象是引用,因此賦默認值的時候最好通過函數(shù),每次都返回一個新對象。
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();
},
},
};
接口地址單獨存放
將接口的定義放到統(tǒng)一文件中,未來變動改動起來會比較方便,如果各個 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);
};
此外,網(wǎng)絡(luò)請求一般都會在 npm 包的基礎(chǔ)上自己再包一層,一方面可以注入共用參數(shù),另一方面可以對返回數(shù)據(jù)進行統(tǒng)一的錯誤處理。
函數(shù)多參數(shù)采用對象
如果定義一個函數(shù)需要 3 個以上的參數(shù)
function(a,b,c,d){
}
此時可以考慮采用對象解構(gòu),改為
function({a=1,b,c,d}={}){
}
好處是未來需要擴展參數(shù)的時候,不需要太擔心其他地方調(diào)用時候傳參是否會引起問題。
當然,如果參數(shù)過多也需要思考一下當前函數(shù)是否承載了太多的功能,進行一下功能上的拆分。
函數(shù)單一職責
當我們已經(jīng)定義了一個函數(shù),比如去初始一些變量。
function initOptions(){
a = xxx
b = xxx
}
此時我們需要做另一件無關(guān)的事 【A】,雖然它和 initOptions? 調(diào)用的時機一致,但最好不要直接放到 initOptions 中,而是新建一個函數(shù)單獨調(diào)用。
不然未來如果其他地方也要調(diào) initOptions?,但此時可能并不需要做【A】這件事情就會引起 bug。
參數(shù)合法性判斷
由于 js 語言的靈活性,函數(shù)傳入的參數(shù)很可能不符合預(yù)期,必要時我們需要進行判斷并且進行兜底處理,不可完全信任調(diào)用方。
團隊合作中,該函數(shù)在未來極大可能會被其他人調(diào)用。
function doSomeThing(params1, params2) {
if(params1 === null){
return;
}
if(params2){
...
}
// 再去做我們的事情
}
如果后邊的流程強依賴于 params?,我們可以直接 return?,必要時也可以上報日志或者 throw Error。
整數(shù)的處理
js? 中沒有整數(shù)類型,即 java? 中的 int、long? 這些,所有數(shù)字都遵循 IEEE 754? 標準,即 java? 中的 double? 類型,詳細的可參考 浮點數(shù)詳解。
可以精確表示的最大整數(shù)是 9007199254740991?,共 16 位,超過這個數(shù)精度可能會丟失,對于新接口,可以問一下后端相應(yīng)數(shù)字字段的最大值會是多少。
對于浮點數(shù)的處理,除了眾所周知的 0.1 + 0.2 === 0.3? 的值為 false 外,當我們對數(shù)字進行運算的時候也需要注意。
常見的將 9.04? 元轉(zhuǎn)為 904 分:
我們需要對結(jié)果進行取整處理。
可選鏈
可選鏈操作符,參考 MDN ,用的比較多。
和后端定的數(shù)組或者對象,后端有時候返回來的很可能是 null 甚至沒有該字段,因此前端可以用可選鏈操作符用于數(shù)組、對象、函數(shù),防止出現(xiàn)錯誤直接阻斷后續(xù)流程。
let nestedProp = obj.first?.second; // 等效于 obj.first && obj.fisrt.second
//后續(xù)流程
但不要過度使用可選鏈,如果某些地方理論上不會出問題,比如 let test = obj.first?.second?,如果 second? 一定能取到,我們直接 let test = obj.first.second 即可。
不然未來如果這里由于某種原因出了問題導(dǎo)致 obj.first? 是 null?,但我們使用了可選鏈,所以 obj.first?.second 也不會報錯,我們就永遠不會知道這里出現(xiàn)問題了。
當然也需要權(quán)衡下,不加可選鏈造成 js Error 會不會影響業(yè)務(wù)邏輯。
對象or數(shù)組引用
修改或者使用對象、數(shù)組時,時刻切記它們?yōu)橐茫惶幮薷臅斐商幪幮薷摹?/p>