说说烂大街的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

作者:以乐之名

本文原创,有不当的地方欢迎指出。转载请指明出处。

JS 中 if / if...else...替换方式的更多相关文章

  1. JS 中如何将<br/> 替换成 /n

    JS 中如何将<br/> 替换成 /n function a() { var data = "aaaa<br/>bbbb<br/>cccc"; ...

  2. JS中5种经典继承方式

    继承 JS中继承的概念: 通过[某种方式]让一个对象可以访问到另一个对象中的属性和方法,我们把这种方式称之为继承 并不是所谓的xxx extends yyy 为什么要使用继承? 有些对象会有方法(动作 ...

  3. JS中 typeof,instanceof类型检测方式

    在js中的类型检测目前我所知道的是三种方式,分别有它们的应用场景: 1.typeof:主要用于检测基本类型. typeof undefined;//=> undefined typeof 'a' ...

  4. js中的replace全局替换

    比如想把str中的所有“&”替换成“&” replace (\&\,"&");只是替换第一个,那么怎么全部都替换呢? replace(new Reg ...

  5. JS中三种字符串连接方式及其性能比较

    工作中经常会碰到要把2个或多个字符串连接成一个字符串的问题,在JS中处理这类问题一般有三种方法,这里将它们一一列出顺便也对它们的性能做个具体的比较. 第一种方法  用连接符“+”把要连接的字符串连起来 ...

  6. js中创建对象的几种方式

    创建对象指创建一个object并给这个对象添加属性和方法,有以下几个方式: 最基本的: var Person={}; Person.name='tom'; Person.age='20'; Perso ...

  7. js中replace的正则替换

    temp: video":"\t<ul class=\"g-list tabview-cont on\">\t\r\n\t\t<li clas ...

  8. js中实现继承的不同方式以及其缺点

    1.利用call和apply,借助构造函数 fucntion P(){ this.name = "P"; } fucntion C1(){ P.call(this); } 解释一下 ...

  9. js教程--从入门到精通 第一篇 js的前世今生以及js中基本数据类型和引入方式

    1.Javascript前世今生   1.1.什么是Javascript       Javascript运行于Javascript [解释器/引擎]中的解释性脚本语言      Javascript ...

随机推荐

  1. cJSON精度丢失问题

    问题复现步骤:1) 输入字符串:{    "V":0.12345678}2) 字符串转成cJSON对象3) 调用cJSON_Print将cJSON对象再转成字符串4) 再将字符串转 ...

  2. linux上搭建solr(用tomcat部署)

    环境centos7 及最新版本solr7 1.先在/usr/local下mkdir solr 2.在里面新建一个tomcat目录 3.拷贝已经解压的tomat到/usr/local/solr/tomc ...

  3. Java用户界面技术

    组件     文本框.复选框.下拉框.文本区域框.列表listbox.按钮.文本标签   布局     layout属性们.panel   java.swing包     JButton     JL ...

  4. bzoj2938(ac自动机)

    刚学了ac自动机,去hzwer上找了道练习题: 串是安全的就说明ac自动机不会找到匹配,考虑ac自动机的匹配过程: 我们把val等于1的点删掉和fail指针指向被删掉的点删掉: 如果剩下的图有环,就有 ...

  5. HDOJ1024--Max Sum Plus Plus(动态规划)UnSolved

    Now I think you have got an AC in Ignatius.L's "Max Sum" problem. To be a brave ACMer, we ...

  6. spark的shuffle机制

    对于大数据计算框架而言,Shuffle阶段的设计优劣是决定性能好坏的关键因素之一.本文将介绍目前Spark的shuffle实现,并将之与MapReduce进行简单对比.本文的介绍顺序是:shuffle ...

  7. mantis邮件设置

     1.cd /var/www/html/mantis     删除 config_inc.php  的$g_enable_email_notification    = OFF;    重启httpd ...

  8. 搭建ELK集群

    环境准备 基础环境介绍 操作系统 部署应用 应用版本号 IP地址 主机名 CentOS 7.4 Elasticsearch/Logstash 6.4.3 192.168.1.1 elk1 CentOS ...

  9. Devexpress中Gridcontrol查找分组

    private void button1_Click(object sender, EventArgs e) { DataTable dt = new DataTable(); dt.Columns. ...

  10. 创建窗口句柄时出错(error creating window handle)

    创建窗口句柄错误.这个错误非常头疼,难以排查,我从网络上搜集了一些排查方案. 可能的原因: 窗口句柄泄露,句柄数超过1W. 用户对象超过1W,错误提示"当前程序已使用了 Window 管理器 ...