重构,对于每个开发者都至关重要,特别是对于那些需要进阶的高级程序员。根据二八理论,20%的重构方法,能解决80%的坏代码。笔者最近查阅较多js编码指南以及重新阅读了《代码整洁之道》、《重构:改善既有代码的设计》两本经典书籍(强烈建议每隔一段时间看,每次都有新体会),整理出以下几个要点,帮助大家以最小的记忆,重构大部分坏代码。如果想全面了解重构方式,可以看笔者整理的AI Javascript风格指南 (opens new window)
坏代码对每个人、每个项目标准都不一样,但以下几点大概率会是坏代码,需要使用重构方法进行代码重构。
好的命名贯穿整个软件编码过程,好命名包括合理使用大小写定义、缩进等。目前前端工程提供很多lint或format工具,能很方便的帮助工程检测和自动化,不清楚的同学可以看看笔者AI前端工具链 (opens new window)。不管是变量名、函数名或是类名,一个好的命名会加快自身开发效率以及阅读代码效率,毕竟程序读的次数会比写的次数多的多。读github上优秀源码就知道,有时候只要看函数名就知道作者的意图。
// bad var yyyymmdstr = moment().format('YYYY/MM/DD'); // good var yearMonthDay = moment().format('YYYY/MM/DD');
Copied!
// bad function dateAdd(date, month) { // ... } let date = new Date(); dateAdd(date, 1) // 很难理解dateAdd(date, 1)是什么意思。笔者注:这里单拎出来举例很简单易懂,但希望在做工程时也时刻谨记这条 // good function dateAddMonth(date, month) { // ... } let date = new Date(); dateAddMonth(date, 1);
Copied!
软件工程中最重要原则之一。刚毕业不久的开发人员容易出现这个问题,觉得业务逻辑很复杂,没办法再细分成单独函数,写出很长的业务函数。但根据笔者指导小伙伴经验,大多数是临时变量过多,导致看不穿业务逻辑的本质;其实重构过程中一步步分解职责,拆分成细小函数并用恰当的名称命名函数名,能很快理解业务的本质,说不定还能发现潜藏的bug。
// bad function handle(arr) { //数组去重 let _arr=[],_arrIds=[]; for(let i=0;i<arr.length;i++){ if(_arrIds.indexOf(arr[i].id)===-1){ _arrIds.push(arr[i].id); _arr.push(arr[i]); } } //遍历替换 _arr.map(item=>{ for(let key in item){ if(item[key]===''){ item[key]='--'; } } }); return _arr; } // good function handle(arr) { let filterArr = filterRepeatById(arr) return replaceEachItem(filterArr) }
Copied!
// bad if (platform.toUpperCase().indexOf('MAC') > -1 && browser.toUpperCase().indexOf('IE') > -1 && wasInitialized() && resize > 0) { // do something } // good let isMacOs = platform.toUpperCase().indexOf('MAC') > -1 let isIEBrowser = browser.toUpperCase().indexOf('IE') > -1 let isResize = resize > 0 if (isMacOs && isIEBrowser && wasInitialized() && isResize) { // do something }
Copied!
// bad const cityStateRegex = /^(.+)[,\\s]+(.+?)\s*(\d{5})?$/; saveCityState(ADDRESS.match(cityStateRegex)[1], ADDRESS.match(cityStateRegex)[2]); // good var cityStateRegex = /^(.+)[,\\s]+(.+?)\s*(\d{5})?$/; var match = ADDRESS.match(cityStateRegex) let [, city, state] = match saveCityState(city, state);
Copied!
// bad if (date.before(SUMMER_START) || date.after(SUMMER_END)) { charge = quantity * _winterRate + _winterServiceCharge } else { charge = quantity * _summerRate } // good if (notSummer(date)) { charge = winterCharge(quantity) } else { charge = summerCharge(quantity) }
Copied!
// bad let getPayAmount = () => { let result if (_isDead) result = deadAmount() else { if (_isSeparated) result = separatedAmount() else { if (_isRetired) result = retiredAmount() else result = normalPayAmount() } } return result } // good let payAmount = () => { if (_isDead) return deadAmount() if (_isSeparated) return separatedAmount() if (_isRetired) return retiredAmount() return normalPayAmount() }
Copied!
// bad let getSpeed = type => { switch (type) { case SPEED_TYPE.AIR: return getAirSpeed() case SPEED_TYPE.WATER: return getWaterSpeed() ... } } // good let speedMap = { [SPEED_TYPE.AIR]: getAirSpeed, [SPEED_TYPE.WATER]: getWaterSpeed } let getSpeed = type => speedMap[type] && speedMap[type]()
Copied!
实践以上列举的重构方法,能解决项目中大部分的坏代码,但还有许多重构方法,能让你的代码变得干净整洁易于阅读。