运算符的代码优化, 可以精简代码, 提高代码可读性
下面主要讨论下逻辑运算符与 &&, 或 ||.
示例:
假设对成长速度显示规定如下:
成长速度为 5 显示 1 个箭头;
成长速度为 10 显示 2 个箭头;
成长速度为 12 显示 3 个箭头;
成长速度为 15 显示 4 个箭头;
其他都显示都显示 0 个箭头.
用代码怎么实现?
- //if else 实现
- var add_level = 0;
- if(add_step == 5){
- add_level = 1;
- } else if (add_step == 10){
- add_level = 2;
- } else if (add_step == 12){
- add_level = 3;
- } else if (add_step == 15){
- add_level = 4;
- } else {
- add_level = 0;
- }
也可以用 switch 实现
- // 用 switch 实现
- var add_level = 0;
- switch(add_step){
- case 5 :
- add_level = 1;
- break;
- case 10 :
- add_level = 2;
- break;
- case 12 :
- add_level = 3;
- break;
- case 15 :
- add_level = 4;
- break;
- default :
- add_level = 0;
- break;
- }
如果需求改成:
成长速度为 > 12 显示 4 个箭头;
成长速度为 > 10 显示 3 个箭头;
成长速度为 > 5 显示 2 个箭头;
成长速度为 > 0 显示 1 个箭头;
成长速度为 <=0 显示 0 个箭头.
你有没有想过用一行就代码实现呢?
- //&& || 实现
- var add_level = (add_step==5 && 1) || (add_step==10 && 2) || (add_step==12 && 3) || (add_step==15 && 4) || 0;
更优雅的方式
- // 更优雅的方式
- var add_level={'5':1,'10':2,'12':3,'15':4}[add_step] || 0;
第二个需求:
var add_level = (add_step>12 && 4) || (add_step>10 && 3) || (add_step>5 && 2) || (add_step>0 && 1) || 0;
讨论区:
几乎所有语言中 || 和 && 都遵循 "短路" 原理, 如 && 中第一个表达式为假就不会去处理第二个表达式, 而 || 正好相反.
js 也遵循上述原则. 但是比较有意思的是它们返回的值.
var attr = true && 4 && "aaa";
那么运行的结果 attr 就不是简单的 true 或这 false, 而是 "aaa"
再来看看 ||:
var attr = attr || "";
这个运算经常用来判断一个变量是否已定义, 如果没有定义就给他一个初始值, 这在给函数的参数定义一个默认值的时候比较有用.
首先我们来梳理一下一个概念, 请你一定要记住: 在 js 逻辑运算中, 0,"",null,false,undefined,NaN 都会判为 false, 其他都为 true(好像没有遗漏了吧, 请各位确认下). 这个一定要记住, 不然应用 || 和 && 就会出现问题.
这里顺便提下: 经常有人问我, 看到很多代码 if(!!attr), 为什么不直接写 if(attr);
其实这是一种更严谨的写法:
请测试 typeof 5 和 typeof !!5 的区别.!! 的作用是把一个其他类型的变量转成的 bool 类型.
再次提醒你记住上面的原则: 如果实参需要是 0,"",null,false,undefined,NaN 的时候也会当 false 来处理.
- if(a>=5){
- alert("你好");
- }
- // 可以改写成
- a>= 5 && alert("你好");
这样只需一行代码就搞定. 但是需要注意的一点: js 中 || 和 && 的特性帮我们精简了代码的同时, 也带来了代码可读性的降低. 这就需要我们自己来权衡了.
扩展
一方面精简 js 代码, 能实质性的减少网络流量, 尤其是大量应用的 js 公用库. 个人比较推荐的做法是: 如果是相对复杂的应用, 请适当地写一些注释. 这个和正在表达式一样, 能够精简代码, 但是可读性会降低, 对读代码的人要求会高些, 最好的办法就是写注释.
我们可以不使用这些技巧, 但是我们一定要能看懂, 因为这些技巧已经广泛应用, 尤其是像 JQuery 等 js 框里的代码, 不理解这些你就很难看懂别人的代码.
像
var Yahoo = Yahoo || {};
这种是非常广泛应用的.
ok, 最后让我们来看一段 jQuery 中的代码吧:
- var wrap =
- // option or optgroup
- !tags.indexOf("<opt") &&
- [ 1, "<select multiple='multiple'>", "</select>" ] ||
- !tags.indexOf("<leg") &&
- [ 1, "<fieldset>", "</fieldset>" ] ||
- tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
- [ 1, "<table>", "</table>" ] ||
- !tags.indexOf("<tr") &&
- [ 2, "<table><tbody>", "</tbody></table>" ] ||
- // <thead> matched above
- (!tags.indexOf("<td") || !tags.indexOf("<th")) &&
- [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] ||
- !tags.indexOf("<col") &&
- [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] ||
- // IE can't serialize <link> and <script> tags normally
- !jQuery.support.htmlSerialize &&
- [ 1, "div<div>", "</div>" ] ||
- [ 0, "","" ];
- // Go to html and back, then peel off extra wrappers
- div.innerHTML = wrap[1] + elem + wrap[2];
- // Move to the right depth
- while ( wrap[0]-- )
- div = div.lastChild;
这段代码是用来处理 $(html) 时, 有些标签必须要约束的, 如 < option > 必须在 < select></select > 之内的.
可能你也发现了还有一个很巧的地方就是 !tags.indexOf("<opt"), 很巧妙的就实现了 startWith 的功能了, 没有一点多余的代码.
扩展总结
例 1: 用于赋值
&&: 从左往右依次判断, 当当前值为 true 则继续, 为 false 则返回此值 (是返回未转换为布尔值时的原值哦)
|| : 从左往右依次判断, 当当前值为 false 则继续, 为 true 则返回此值 (是返回未转换为布尔值时的原值哦)
- // => aaa
- var attr = true && 4 && "aaa";
- // => 0
- var attr = true && 0 && "aaa";
- // => 100
- var attr = 100 || 12;
- // => e
- var attr = "e" || "hahaha"
- // => hahaha
- var attr = ""||"hahaha"
例 2 经过多次判断的赋值
- /*
- x>=15 时 => 4
- x>=12 时 => 3
- x>=10 时 => 2
- x>=5 时 => 1
- x<5 时 => 0
- */
- console.log((x>=15 && 4) || (x>=12 && 3) || (x>=10 && 2) || (x>=5 && 1) || 0);
例 3 与对象形式的变量合体
- /*
- x=15 时 => 4
- x=12 时 => 3
- x=10 时 => 2
- x=5 时 => 1
- 其它 => 0
- */
- console.log( {'5':1,'10':2,'12':3,'15':4}[x] || 0 );
例 4 用于执行语句
- if(a>=5){alert("你好");}
- // 可以写成:
- a>= 5 && alert("你好");
给向往远方的你:
没有比脚更长的路, 没有比人更高的山.
来源: http://www.jianshu.com/p/ccad8285e735