JS 中 if / if...else...替换方式
if/if...else...替换方式
说说烂大街的if/if...else...,程序中用得最多的流程判断语句。
对着曾经满屏的if/if...else...,心想能不能搞点事情,折腾点浪花浪里呀浪。
对顶着“这个需求很简单,怎么实现我不管,明天上线”的程序猿,答案必须YES。
"Write Less, Do More",学习进步的本质就是为了更有效率地偷懒。
废话说完,直接上方法汇总,让我们来一窥究竟:
switch改写if
// if 版本var a = 1;if(a > 1 && a < 5) {    return 1} else if(a > 5 && a < 10){    return 5}else{    return 10}// switch 改版switch(true){    case (a > 1 && a < 5):        return 1
    case (a > 5 && a < 10):        return 5
    default:        return 10}以上代码的switch...case...的用法实际使用不多,仅供参考。
一般case为常量时switch...case...用得较多。
选择分支较多时,建议选用switch…case可提高程序的效率,但switch...case不足的地方在于只能处理字符或者数字类型的变量,if…else更加灵活,可用于判断表达式是否成立,比如if(a+b>c),if…else的应用范围更广。
三元运算符改写if
// if 版本if (bool) {
    value = 1;
} else {
    value = 2;
}// 三元运算符 版本value = bool ? 1 : 2;// 三元预算符 多个运算需要括号包裹 此处用了逗号表达式return typeof foo === 'object'?(console.log(1),1):(console.log(2),2);优点:代码简化,更加清爽,write less
缺点:复杂的三元运算符可读性较差,需友好注释
TIPS: 三元运算符后面不能带return
// 错误用法,运算符号后不能带returnbool ? return 1 : return 2;
逻辑判断 and(&&)和or(||) 改写if
原理:利用逻辑判断的短路运算来实现
短路:
&&中第一个表达式为假就不会去处理第二个表达式,||则相反
// if为真if (bool) {
    value = getYes();
}// &&改版bool && (value = getYes());// if为假if (!bool) {
    value = getNo();
}bool || (value = getNo());优点:代码简化,更加清爽,write less
缺点:适用于简单判断逻辑,复杂的判断运算可读性较差,需友好注释
TIPS:适用于没有else的场景, 逻辑运算符后面不能带return
// 错误用法,运算符号后不能带returnboll || return true;
知识点插播 —— (1)
- 三元运算符和逻辑运算符都有一层return作用,但不可作用于函数return语句,所以像以下这种用法都是错误的; 
// 错误用法function getResult(value) {
    value ? 'yes' : 'no';
}var result = getResult(true); // 并不会有值返回- js逻辑运算中, - 0/""/null/false/undefined/NaN都会判为- false,其它都为- true;
- 很多开源代码中可见 - if(!!attr),为什么不直接写- if(attr), 其实这是一种更严谨的写法,- !!attr会强制转化为boolean类型。- typeof !!attr == true比- typeof attr == true更加严谨。
对象属性
// if版本if (a == 1) {    return 'one';
} else if (a == 2) {    return 'two';
} else if (a == 3) {    return 'three';
} else {    return '';
}// 对象属性 改版var ret = {    1: 'one',    2: 'two',    3: 'three'};return ret[a] ? ret[a] : '';TIPS:
- 判断值需为确定值,如 - ==,其它如- >=/<=/>/<不适用
- 条件作为对象属性,需要注意对象属性的读取方式 
知识点插播 —— (2)
JS的命名规则(变量的命名规则)
- 标识符只能由字母、数字、下划线和‘$’组成 
- 数字不可以作为标识符的首字符 
对象属性的命名规则
- 通过 - []操作符为对象添加属性时,属性名可以是任何字符串(包括只包含空格的字符串和空字符串);
- 通过 - .操作符为对象添加属性时,属性名必须是合法的标识符名称;
- 如果属性名包含非法的标识符字符,则只能采用 - obj[“propertyName”]的形式;
- 如果属性名是合法的标识符,读取时可采用 - obj.propertyName或- obj[“propertyName”]的形式;
策略模式
策略模式:定义一系列的算法,把它们一个个封装起来,目的就是将算法的使用与算法的实现分离开来
以下为常见的表单验证,用策略模式来构建,替换if...else的方式
// html<form id = "registerForm" method="post" action="http://xxxx.com/api/register">
    用户名:<input type="text" name="userName">
    密码:<input type="text" name="password">
    手机号码:<input type="text" name="phoneNumber">
    <button type="submit">提交</button>
</form>// js// 策略对象var strategies = {
    isNoEmpty: function (value, errorMsg) {        if (value === '') {            return errorMsg;
        }
    },
    isNoSpace: function (value, errorMsg) {        if (value.trim() === '') {            return errorMsg;
        }
    },
    minLength: function (value, length, errorMsg) {        if (value.trim().length < length) {            return errorMsg;
        }
    },
    maxLength: function (value, length, errorMsg) {        if (value.length > length) {            return errorMsg;
        }
    },
    isMobile: function (value, errorMsg) {        if (!/^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|17[7]|18[0|1|2|3|5|6|7|8|9])\d{8}$/.test(value)) {            return errorMsg;
        }                
    }
}// 验证类var Validator = function() {
    this.cache = [];
}
Validator.prototype.add = function(dom, rules) {    var self = this;    for(var i = 0, rule; rule = rules[i++];) {
        (function(rule) {            var strategyAry = rule.strategy.split(':');            var errorMsg = rule.errorMsg;            self.cache.push(function() {            var strategy = strategyAry.shift();
            strategyAry.unshift(dom.value);
            strategyAry.push(errorMsg);            return strategies[strategy].apply(dom, strategyAry);
            })
        })(rule)
    }
};
Validator.prototype.start = function() {    for(var i = 0, validatorFunc; validatorFunc = this.cache[i++];) {        var errorMsg = validatorFunc();        if (errorMsg) {            return errorMsg;
        }
    }
};// 调用代码var registerForm = document.getElementById('registerForm');var validataFunc = function() {    var validator = new Validator();
    validator.add(registerForm.userName, [{
        strategy: 'isNoEmpty',
        errorMsg: '用户名不可为空'
    }, {
        strategy: 'isNoSpace',
        errorMsg: '不允许以空白字符命名'
    }, {
        strategy: 'minLength:2',
        errorMsg: '用户名长度不能小于2位'
    }]);
    validator.add(registerForm.password, [ {
        strategy: 'minLength:6',
        errorMsg: '密码长度不能小于6位'
    }]);
    validator.add(registerForm.phoneNumber, [{
        strategy: 'isMobile',
        errorMsg: '请输入正确的手机号码格式'
    }]);    var errorMsg = validator.start();    return errorMsg;
}
registerForm.onsubmit = function() {    var errorMsg = validataFunc();    if (errorMsg) {
        alert(errorMsg);        return false;
    }
}- 第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程; 
- 第二个部分是环境类Context,该Context接收客户端的请求,随后把请求委托给某一个策略类; 
优点:
- 有效避免多重条件选择语句 
- 提供了对外开放 - 封装原则的完美支持,将方法封装在独立的strategy中,使得它们易于切换、易于理解、易于扩展。 
- 复用性 
缺点:
- 增加了策略类/对象的使用 
- 使用策略模式,必须先了解所有的strategy,违反了最少知识原则 
参考资料
作者:以乐之名
本文原创,有不当的地方欢迎指出。转载请指明出处。
作者:以乐之名
链接:https://www.jianshu.com/p/d49091d6b84e
共同学习,写下你的评论
评论加载中...
作者其他优质文章
 
                 
            
 
			 
					 
					