代码重构

2016-10-12 曹强 更多博文 » 博客 » GitHub »

javascript

原文链接 https://ronghuaxueleng.github.io/2016/10/12/JavaScript%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B8%8E%E5%BC%80%E5%8F%91%E5%AE%9E%E8%B7%B5-21%E4%BB%A3%E7%A0%81%E9%87%8D%E6%9E%84/
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。



一些重构的建议:

  1. 提炼函数
* 避免出现超大函数

* 独立出来的函数有助于代码复用

* 独立出来的函数更容易被覆写

* 独立出来的函数如果拥有一个良好的命名,

* 它本身就起到了注释的作用。

比如在一个负责取得用户信息的函数里面,我们还需要打印跟用户信息有关的log,那么打印log的语句就可以被封装在一个独立的函数里:

var getUserInfo = function() {
    ajax('http://xxx.com/userInfo', function(data) {
        console.log('userId: ' + data.userId);
        console.log('userName: ' + data.userName);
        console.log('nickName: ' + data.nickName);
    });
};

可以改成:

var getUserInfo = function() {
    ajax('http://xxx.com/userInfo', function(data) {
        printDetails(data);
    });
};
var printDetails = function(data) {
    console.log('userId: ' + data.userId);
    console.log('userName: ' + data.userName);
    console.log('nickName: ' + data.nickName);
}
  1. 合并重复的条件片段
    如果一个函数内有一些条件分支语句,而这些条件分支语句内部散步了一些重复的代码,那么就有必要进行合并去重工作。

    //页面跳转 var paging = function(currPage) { if (currPage <= 0) { currPage = 0; jump(currPage); //跳转 } else if (currPage >= totalPage) { currPage = totalPage; jump(currPage); //跳转 } else { jump(currPage); //跳转 } }

改成

//页面跳转
var paging = function(currPage) {
    if (currPage <= 0) {
        currPage = 0;
    } else if (currPage >= totalPage) {
        currPage = totalPage;
    } 
    jump(currPage); //跳转
}
  1. 把条件分支语句提炼成函数
    在程序设计中,复杂的条件分支语句是导致程序难以阅读和理解的重要原因,而且容易导致一个庞大的函数,所以通常我们要进行一定的提炼。

    //计算商品价格,如果处于夏季,全部商品八折出售 var getPrice = function(price) { var date = new Date(); if (date.getMonth() >= 6 && date.getMonth <= 9) { //夏季 return price * 0.8; } return price; }

改成

//计算商品价格,如果处于夏季,全部商品八折出售
var getPrice = function(price) {

    if (isSummer()) { //夏季
        return price * 0.8;
    }
    return price;
}
var isSummer = function() {
    var date = new Date();
    return date.getMonth() >= 6 && date.getMonth <= 9;
}
  1. 合理使用循环

    var createXHR = 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 = createXHR();

改成:

var createXHR = function() {
    var versions = ['MSXML2.XMLHttp.6.0', 'MSXML2.XMLHttp.3.0', 'MSXML2.XMLHttp'];
    for (var i = 0, version; version = versions[i++]; ) {
        try {
            return new ActiveObject(version);
        } catch(e) {

        }
    }
};
var xhr = createXHR();
  1. 提前让函数退出代替嵌套条件分支

    var del = function(obj) { var ret; if (!obj.isReadOnly) { //不为只读的时候才可以删除 if (obj.isFolder) { //如果是文件夹 ret = deleteFolder(obj); } else if (obj.isFile) { //如果是文件 ret = deleteFile(obj); } } return ret; }

改成:

var del = function(obj) {
    if (obj.isReadOnly) { 
        return;
    }
    if (obj.isFolder) { //如果是文件夹
        return deleteFolder(obj);
    } 
    if (obj.isFile) { //如果是文件
        return deleteFile(obj);
    }
}
  1. 传递对象参数代替过长的参数列表
    有时候一个函数可能接收多个参数,而参数的数量越多函数就越难理解和使用。这时我们可以把参数放入一个对象内,然后把对象传入。

    var setUserInfo = function(id, name, address, sex, mobile, qq) { console.log('id=' + id); console.log('name=' + name); console.log('address=' + address); console.log('sex=' + sex); console.log('mobile=' + mobile); console.log('qq=' + qq); } setUserInfo(1234, cyseria, guangzhou, female, 188*, 52*);

改成:

var setUserInfo = function(obj) {
    console.log('id=' + obj.id);
    console.log('name=' + obj.name);
    console.log('address=' + obj.address);
    console.log('sex=' + obj.sex);
    console.log('mobile=' + obj.mobile);
    console.log('qq=' + obj.qq);
}
setUserInfo({
    id: 1234, 
    name: cyseria, 
    address: guangzhou, 
    sex: female, 
    mobile: 188***, 
    qq: 52***
});
  1. 尽量减少参数数量
    尽量减少一些没必要的不会使用或者可以求出的参数。这里不做过多阐述。

  2. 少用三目运算
    有时候我们用三目运算会觉得它性能高,代码量少。但是在实际开发中,即使把一段代码循环一百万次,使用三目运算和if,else的时间开销依旧在同个级别中。同样,相比损失的代码可读性和可维护性,他能节省的代码量可以忽略不计。

至于例子,看看下面那个你就知道了:

if (!aup || bup) {
    return a === doc ? -1 :
        b === doc ? 1 : 
        aup ? -1 : 
        bup : -1 :
        sortInput ? (indexOf.call(sortInput, a) - indexOf.call(sortInput, b)) : 
        0;
}

当然,如果只是简单的一句,用一下也没什么所谓。

  1. 合理使用链式调用
    使用jq的对链式调用一定不陌生,在自己编写函数的时候也可以使用这点,返回自身。但是他也有一个坏处,调试的时候不方便。所以如果链条的结构稳定后期不易修改,那么使用他无可厚非,但是如果该链经常发生变化那么还是用普通的调用吧。

    var User = { id: null, name: null, setId: function(id) { this.id = id; return this; }, setName: function(name) { this.name= name; return this; } }; console.log(User.setId(1234).setName('cyseria'));

  2. 分解大型类

    var Spirit = function(name) { this.name = name; }; Spirit.prototype.attack = function(type) { if (type === 'waveBoxing') { console.log(this.name + ':使用波动拳'); } else if (type === 'whirlKick') { console.log(this.name + ':使用旋风腿'); } }; var Spirit = new Spirit('AAA'); Spirit .attack('waveBoxing'); Spirit .attack('whirlKick');

改成:

var Attack = function(spirit) {
    this.spirit = spirit;
};
Attack.prototype.start = function(type) {
    return this.list[type].call(this);
}
Attack.prototype.list= function(type) {
    waveBoxing: function() {
        console.log(this.spirit.name + ':使用波动拳');
    },
    whirlKick: function() {
        console.log(this.spirit.name + ':使用旋风腿');
    }
};
var Spirit = function(name) {
    this.name = name;
    this.attackObj = new Attack(this);
};
Spirit.prototype.attack = function(type) {
    this.attackObj.start(type);
};

var Spirit = new Spirit('AAA');
Spirit .attack('waveBoxing');
Spirit .attack('whirlKick');
  1. 用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); } } } }; func();