这是《 javaScript设计模式与开发实践 》一书的最后一章"代码重构"。javascript
如下的一些方法不是必须严格遵照的标准,选择实践哪些,以及如何实现这都需根据状况而定(是否是有充足时间)java
若是在函数中有一段代码能够独立出来,那么最好把这些代码放进另一个独立的函数当中去。好处有:ajax
避免出现超大型函数。编程
独立出来的函数有助于代码复用。设计模式
独立出来的函数更加容易被改写,减小维护成本。浏览器
独立出来的函数若是有一个良好的命名,自己就起到了注释的做用。编程语言
例如一个获取用户信息的函数,咱们还须要打印用户信息,这种状况下就能够独立出打印信息的代码。函数
var getUserInfo = function() { ajax('http://xxx/userInfo', function(data) { console.log('userId: ' + data.userId); console.log('userName: ' + data.userName); console.log('nickName: ' + data.nickName); }); };
改写:oop
var getUserInfo = function() { ajax('http://xxx/userInfo', function(data) { printUserInfo(data); }); }; var printUserInfo = function(data) { console.log('userId: ' + data.userId); console.log('userName: ' + data.userName); console.log('nickName: ' + data.nickName); };
若是一个函数内有一些条件语句,而条件语句内散布了一些重复代码,就有必要进行合并去重工做。设计
例如一个分页函数paging
,函数接受一个currpage
表示挑战页码,在跳转前须要判断currpage
是否在有效的取值范围。
var paging = function(currpage) { if (currpage <= 0) { currpage = 0; jump(currpage); // 跳转 } else if (currpage >= totalPage) { // 总页数totalPage currpage = totalPage; jump(currpage); // 跳转 } else { jump(currpage); // 跳转 } }
负责跳转的jump(currpage)
在每一个条件分支都出现了,因此彻底把这句代码独立出来:
var paging = function(currpage) { if (currpage <= 0) { currpage = 0; } else if (currpage >= totalPage) { // 总页数totalPage currpage = totalPage; } jump(currpage); // 跳转 }
在程序设计中,复杂的条件语句是致使程序难以阅读和理解的重要缘由,并且容易增大函数代码量。例如以一个计算商品价格的getPrice
函数,商品计算有个规则,夏天商品以8折出售。
var getPrice = function(price) { var date = new Date; if (date.getMonth() >= 6 && date.getMonth() <= 9 ) { // 处于夏天 return price * 0.8 } return price; }
其中的条件语句if (date.getMonth() >= 6 && date.getMonth() <= 9 )
若是改写提炼成一个独立的函数,既能更准确的表达代码的意思,函数名又能起到注释做用。
var isSummer = function() { var dateMonth = (new Date).getMonth(); return dateMonth >= 6 && dateMonth <= 9 ; }; var getPrice = function(price) { var date = new Date; if ( isSummer() ) { // 处于夏天 return price * 0.8 } return price; };
在函数体内,若是有些代码是负责一些重复性的工做,那么合理使用循环不只能够完成一样的功能,还可使代码量更少,有一段建立XHR对象的代码,为了简化代码,只检测IE9已下的浏览器。
var creatXHR = function() { var xhr; try{ xhr = new ActiveXObject('MSXML2.XMLHTTP.6.0'); } catch(e) { try{ xhr = new ActiveXObject('MSXML2.XMLHTTP.3.0'); } catch(e) { xhr = new ActiveXObject('MSXML2.XMLHTTP'); } } return xhr; }; var xhr = creatXHR();
下面灵活的使用循环,能够获得上面代码同样的效果:
var creatXHR = function() { var versions = ['MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP']; for (var i = 0;i < versions.length; i++) { try{ return new ActiveObject( version[i] ); }catch(e) { } } }; var xhr = creatXHR();
初学者可能有这样一个观念:”每一个函数只能有一个入口和一个出口。”现代编程语言都会限制函数有一个入口。可是关于”函数只有一个出口”,每每有不同的见解。
下面是一个遵照“函数只有一个出口”的代码。
var del = fucntion(obj) { var ret; if (!obj.isReadOnly) { // 不为只读才能删除 if (obj.isFolder) { // 判断文件夹 ret = deletFolder(obj); } else if (obj.isFile) { // 判断文件 ret = deletFile(obj); } } return ret; }
嵌套的条件分支语句是代码维护者的噩梦,若是对函数的剩余部分不感兴趣,那就应该当即退出。
咱们能够挑选一些条件分支,在进入这些条件分支后,就当即让函数退出。有一个常见的技巧。在面对一个嵌套的if分支时,咱们能够把外层if表达式进行反转。例如:
var del = function(obj) { if (obj.isReadOnly) { // 反转表达式 return; } if (obj.isFolder) { return deletFolder(obj); } if (obj.isFile) { return deletFile(obj); } }
函数可能接受多个参数,参数越多函数就越难理解和使用。
setUserInfo(1111, 'sven', 'hangzhou', 'male', '137*****') // 可改写成 setUserInfo({ id: 1111, name: 'sven', address: 'hangzhou', sex: 'male', mobile: '137*****' })
改写后能够再也不关心参数的数量和顺序,通常参数控制在4个之内,超过4个就须要转化成对象形式。
链式调用在调试的时候很是不方便,若是一条调用链中有错误出现,必需要把这条调用链拆开才能定位错误出现的地方。
若是该链条的结构稳定,后期不易发生修改,使用链式调用无可厚非,可是若是该链条容易发生变化,致使调试和维护困难,那么普通调用形式为佳。
若是一个类的方法足够复杂和庞大,那么它彻底有必要做为一个单独的类存在。面向对象设计鼓励将行为分布在合理数量的更小对象之中。
在函数有两重循环语句时,咱们每每须要在内层循环中判断,当达到临界条件时退出外层循环,有如下实现方式。
设置flag。
var func = function() { var flage = false; for (var i = 0; i < 10; i++) { for (var j = 0; j < 10; j++) { if (i * j > 30) { flag = true; break; } } if (flag === true) { break; } } }
设置循环标记
var func = function() { outerloop: for(var i = 0; i < 10; i++) { innerloop: for(var j = 0; j < 10; j++) { if (i * j >30) { break outerloop; } } } }
这两种作法都让人头晕目眩,更简单的作法是直接终止整个方法:
var func = function() { for (var i = 0; i < 10; i++) { for (var j = 0; j < 10; j++) { if (i * j > 30) { return; } } } }
用return
直接退出有一个问题,在循环以后若是还有代码就没法执行:
var func = function() { for (var i = 0; i < 10; i++) { for (var j = 0; j < 10; j++) { if (i * j > 30) { return; } } } console.log(i); // 没法执行 }
咱们能够把循环后须要的代码放到return
后面,若是代码较多,能够提炼成一个单独的函数。
var print = function(i) { console.log(i); }; var func = function() { for (var i = 0; i < 10; i++) { for (var j = 0; j < 10; j++) { if (i * j > 30) { return print(i); } } } };