说说烂大街的 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)
三元运算符和逻辑运算符都有一层 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.cnblogs.com/kenz520/p/9312075.html