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

// 错误用法,运算符号后不能带return
bool ? 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

// 错误用法,运算符号后不能带return
boll || return true;

知识点插播 —— (1)

  1. 三元运算符和逻辑运算符都有一层return作用,但不可作用于函数return语句,所以像以下这种用法都是错误的;
// 错误用法
function getResult(value) {
    value ? 'yes' : 'no';
}
var result = getResult(true); // 并不会有值返回
  1. js逻辑运算中,0/""/null/false/undefined/NaN都会判为false,其它都为true
  2. 很多开源代码中可见if(!!attr),为什么不直接写if(attr), 其实这是一种更严谨的写法,!!attr会强制转化为boolean类型。typeof !!attr == truetypeof 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:

  1. 判断值需为确定值,如== ,其它如>=/<=/>/<不适用
  2. 条件作为对象属性,需要注意对象属性的读取方式

知识点插播 —— (2)

JS的命名规则(变量的命名规则)
  • 标识符只能由字母、数字、下划线和‘$’组成
  • 数字不可以作为标识符的首字符
对象属性的命名规则
  • 通过[]操作符为对象添加属性时,属性名可以是任何字符串(包括只包含空格的字符串和空字符串);
  • 通过.操作符为对象添加属性时,属性名必须是合法的标识符名称;
  • 如果属性名包含非法的标识符字符,则只能采用obj[“propertyName”]的形式;
  • 如果属性名是合法的标识符,读取时可采用obj.propertyNameobj[“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接收客户端的请求,随后把请求委托给某一个策略类;

优点:

  1. 有效避免多重条件选择语句
  2. 提供了对外开放 - 封装原则的完美支持,将方法封装在独立的strategy中,使得它们易于切换、易于理解、易于扩展。
  3. 复用性

缺点:

  1. 增加了策略类/对象的使用
  2. 使用策略模式,必须先了解所有的strategy,违反了最少知识原则

参考资料

  1. JavaScript设计模式之策略模式
  2. js减少if语句的技巧
  3. js对象属性的命名规则
  4. javascript中||和&&代替if

作者:以乐之名
本文原创,有不当的地方欢迎指出。转载请指明出处。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342