重构如何在javascript中切换以获得更干净的代码

How refactor switch in javascript for cleaner code?

本文关键字:代码 javascript 重构      更新时间:2023-09-26

我正在尝试编写一些更干净的Javascript/jQuery代码。如何将此函数重构为更干净、更小的函数。看来肯定有更好的方法可以做到这一点。它是有效的,但我相信有更好的方法来编写这样的函数。提前感谢!

function filterForm(purpose, entry) {
    switch (purpose) {
        case 'Business' : 
            switch (entry) {
                case 'Single': 
                    $("#moreq1").css( "display", "block" );   
                    $("#moreq2").css( "display", "none"  );   
                    $("#moreq3").css( "display", "none"  );  
                    break;
                case 'Double': 
                    $("#moreq1").css( "display", "block" );   
                    $("#moreq2").css( "display", "none"  );   
                    $("#moreq3").css( "display", "none"  );  
                    break;
                case 'Multiple' : 
                    $("#moreq1").css( "display", "block" );   
                    $("#moreq2").css( "display", "block" );   
                    $("#moreq3").css( "display", "none"  );  
                    break;
                }
                break;
            case 'Private' : 
                switch (entry) {
                    case 'Single'   : 
                        $("#moreq1").css( "display", "block" );   
                        $("#moreq2").css( "display", "none"  );   
                        $("#moreq3").css( "display", "none"  );  
                        break;
                    case 'Double'   : 
                        $("#moreq1").css( "display", "none"  );   
                        $("#moreq2").css( "display", "none"  );   
                        $("#moreq3").css( "display", "none"  );  
                        break;
                    case 'Multiple' : 
                        $("#moreq1").css( "display", "none"  );   
                        $("#moreq2").css( "display", "none"  );   
                       $("#moreq3").css( "display", "none"  );  
                        break;
                }   
                break;
            case 'Tourist' : 
                switch (entry) {
                    case 'Single'   : 
                        $("#moreq1").css( "display", "block" );   
                        $("#moreq2").css( "display", "none"  );   
                        $("#moreq3").css( "display", "block"  );  
                        break;
                    case 'Double'   : 
                        $("#moreq1").css( "display", "none" );   
                        $("#moreq2").css( "display", "none"  );   
                        $("#moreq3").css( "display", "none"  );  
                        break;
                    case 'Multiple' : 
                        $("#moreq1").css( "display", "none"  );   
                        $("#moreq2").css( "display", "none" );   
                        $("#moreq3").css( "display", "none" );  
                        break;
                }       
                break;
            }
    }
}

虽然其他答案在组合可能性方面做得很好,但对我来说,使用所有可能性的"地图"似乎更合乎逻辑,并引用:

var filterForm = (function () {
    var moreq = [
        "",        // So you can use indexes starting at 1
        "moreq1",
        "moreq2",
        "moreq3"
    ], Purposes = {
        "Business": {
            "Single": [moreq[1]],
            "Double": [moreq[1]],
            "Multiple": [moreq[1], moreq[2]]
        },
        "Private": {
            "Single": [moreq[1]],
            "Double": [],
            "Multiple": []
        },
        "Tourist": {
            "Single": [moreq[1], moreq[],
            "Double": [],
            "Multiple": []
        }
    };
    return function (purpose, entry) {
        var i, j, cur, display;
        for (i = 1, j = moreq.length; i < j; i++) {
            cur = moreq[i];
            display = Purposes[purpose][entry].indexOf(cur) > -1 ? "block" : "none";
            console.log("Setting " + cur + " as " + display);
            //$("#" + cur).css("display", display);
        }
    };
}());
filterForm("Business", "Multiple");

演示:http://jsfiddle.net/w3Jnn/1/

对象中的数组是要将显示设置为block的元素。一旦要更改特定设置,只需修改Purposes对象的数组即可。

当然,我的函数不会对Purposes[purpose][entry].indexOf(cur) > -1部分进行太多检查——它假设purposeentry参数将具有有效值。这可以修改以进行检查,但现在似乎并不重要。

值得注意的是,这使用了一个闭包(周围的(function () { }))来实例化Purposesitems变量一次,但将它们排除在全局范围之外。

另外请注意,并非所有浏览器(主要是旧IE)都支持Array.indexOf方法,因此在https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf#Compatibility包括在你的页面上以确保它的工作,以及你可以在谷歌上找到的其他内容。

在查看了您的所有条件后,似乎可以归结为:

function filterForm(purpose, entry) {
    var q1 = purpose == 'Business' || entry == 'Single' ? 'block' : 'none';
    var q2 = purpose == 'Business' && entry == 'Multiple' ? 'block' : 'none';
    var q3 = purpose == 'Tourist' && entry == 'Single' ? 'block' : 'none';
    $("#moreq1").css( "display", q1 );   
    $("#moreq2").css( "display", q2 );   
    $("#moreq3").css( "display", q3 ); 
}

我不确定我有多喜欢这种方式,但这是一种非开关、非if的方式。它也有助于测试,因为你可以独立地对查找进行单元测试。

但是,如果目的条目不是查找中的键,则会引发一些错误。

function filterForm(purpose, entry) {
    var lookup = {}
    lookup['Business'] = {'Single':{'q1':'block','q2':'none','q3':'none'},
                         {'Double':{'q1':'block','q2':'none','q3':'none'}};
    lookup['Private'] = {...etc...};
    $('#moreq1').css('display', lookup[purpose][entry]['q1]);
}

我会从删除所有隐藏的语句开始——只是一般地隐藏所有语句,然后只显示那些需要的语句(这里使用if-语句,请参阅@nmynarcik的答案,了解使用switches的中间步骤):

function filterForm(purpose, entry) {
    $("#moreq1, #moreq2, #moreq3").css("display", "none");
    if (purpose == 'Business') {
        $("#moreq1").css("display", "block");
        if (entry == 'Multiple')
            $("#moreq2").css("display", "block");
    } else if (purpose == 'Private' && entry == 'Single')
         $("#moreq1").css("display", "block");
    } else if (purpose == 'Tourist' && entry == 'Single') {
         $("#moreq1, #moreq3").css("display", "block");
    }
}

可以进一步简化为

function filterForm(purpose, entry) {
    $("#moreq1, #moreq2, #moreq3").css("display", "none");
    if (purpose == 'Business' || entry == 'Single')
         $("#moreq1").css("display", "block");
    if (purpose == 'Business' && entry == 'Multiple')
         $("#moreq2").css("display", "block");
    if (purpose == 'Tourist' && entry == 'Single')
         $("#moreq3").css("display", "block");
}

如果它变得越来越复杂,我建议为单个显示值使用查找映射,而不是使用具有大量重复语句的switch语句。对于您的设置,它看起来像

var show = {
    "moreq1": {
        "Business": true,
        "Private": {
            "Single": true
        },
        "Tourist": {
            "Single": true
        }
    },
    "moreq2": {
        "Business": {
            "Multiple": true
        }
    },
    "moreq3": {
        "Tourist": {
             "Single": true
        }
    }
};
for (var id in show) {
    var l = show[id];
    $("#"+id).css("display", l[purpose] === true || l[purpose] && l[purpose][entry] ? "block" : "none");
}

当然,如果purposeentry的顺序变短,您可以交换。

如果你想坚持使用switched,给它们一个类,你可以设置all显示:none;当你开始你的方法。

然后执行:

function filterForm(purpose, entry) {
   $('.qItem').hide();
    switch (purpose) {
        case 'Business' : 
            $("#moreq1").css( "display", "block" );
            switch (entry) {
                case 'Multiple' : 
                    $("#moreq2").css( "display", "block" );
                break;
            }
        break;
        case 'Private' : 
            switch (entry) {
                case 'Single'   : 
                    $("#moreq1").css( "display", "block" );   
                    break;
            }   
        break;
        case 'Tourist' : 
            switch (entry) {
                case 'Single'   : 
                    $("#moreq1").css( "display", "block" );   
                    $("#moreq3").css( "display", "block"  );  
                break;
            }       
        break;
    }
}

您可以在此处查看类的使用方式:http://jsfiddle.net/pMfgy/

正如许多人所说,看起来可以大大简化显示逻辑,但如果基于purposeentry变量值维护基于moreq1moreq2moreq3元素的不同状态对您来说很重要,那么我建议您将大部分显示"逻辑"转移到CSS,而不是JS/jQuery。

大部分逻辑可以用与purposeentry值绑定的CSS样式定义来替换:

CSS

// "Business" display styles
// "Business - Single" display styles
.business.single #moreq1 {display: block}
.business.single #moreq2,
.business.single #moreq3 {display: none}
// "Business - Double" display styles
.business.double #moreq1 {display: block}
.business.double #moreq2,
.business.double #moreq3 {display: none}
// "Business - Multiple" display styles
.business.multiple #moreq1,
.business.multiple #moreq2 {display: block}
.business.multiple #moreq3 {display: none}
// "Private" display styles
// "Private - Single" display styles
.private.single #moreq1 {display: block}
.private.single #moreq2,
.private.single #moreq3 {display: none}
// "Private - Double" display styles
.private.double #moreq1,
.private.double #moreq2,
.private.double #moreq3 {display: none}
// "Private - Multiple" display styles
.private.multiple #moreq1,
.private.multiple #moreq2,
.private.multiple #moreq3 {display: none}
// "Tourist" display styles
// "Tourist - Single" display styles
.tourist.single #moreq1,
.tourist.single #moreq3 {display: block}
.tourist.single #moreq2 {display: none}
// "Tourist - Double" display styles
.tourist.double #moreq1,
.tourist.double #moreq2,
.tourist.double #moreq3 {display: none}
// "Tourist - Multiple" display styles
.tourist.multiple #moreq1,
.tourist.multiple #moreq2,
.tourist.multiple #moreq3 {display: none}

之后,您可以使用jQuery将样式简单地分配给父容器(甚至是<body>标记),使用purposeentry值:

JS

function filterForm(purpose, entry) {
    var dynamicClasses = purpose + " " + entry;
    $("#parent_element_ID").addClass(dynamicClasses.toLowerCase());
}

这时,CSS将接管并显示基于您的CSS规则的元素。

虽然它看起来像是很多CSS,但它不仅将CSS用于其预期目的,而且还进行任何更改(或添加新的部分),一个简单的CSS更新,而不是JS代码更改。

试试这个:

function filterForm(purpose, entry) {
    var hideMap = {
        Business: {
            Single: [2, 3],
            Double: [2, 3],
            Multiple: [3]
        },
        Private: {
            Single: [2, 3],
            Double: [1, 2, 3],
            Multiple: [1, 2, 3]
        },
        Tourist: {
            Single: [2],
            Double: [1, 2, 3],
            Multiple: [1, 2, 3]
        }
    };
    hideShow(hideMap[purpose][entry]);
}
function hideShow(a) {
    var allEls = '#moreq1, #moreq2, #moreq3';
    for (var i = 0; i < a.length; i++) {
        a[i] = '#moreq' + a[i];
    }
    var hideEls = a.join(',');
    $(hideEls).hide(a.join());
    $(allEls).not(hideEls).show();
}

jsFiddle