前端要给力之:代码可以有多烂?
1、烂代码是怎么定义的?
!KissyUI是淘宝Kissy这个前端项目的一个群,龙藏同学在看完我在公司内网的“读烂代码系列”之后就在群里问呵:烂代码是怎么定义的?
是呵,到底什么才算烂代码呢?这让我想到一件事,是另一个网友在gtalk上问我的一个问题:他需要a,b,c三个条件全真时为假,全假时也为假,请问如何判断。
接下来KissyUI群里的同学给出了很多答案:
[javascript]view plaincopy- //1.圆心
- if(a&&b&&c||!a&&!b&&!c){
- returnfalse
- }
- //2.龙藏
- (a^b)&c
- //3.愚公(我给gtalk上的提问者)的答案
- (axorb)or(axorc)
- //4.提问者自己的想法
- (a+b+c)%3
- //5.云谦对答案4的改进版本
- (!!a+!!b+!!c)%n
- //6.拔赤
- a?(b?c:b):(b?!b:!c)
- //7.吴英杰
- (a!=b||b!=c)
- 或
- (!a!=!b||!b!=!c)
- //8.姬光
- varv=a&&b&&c;
- if(!v){
- returnfalse;
- }elseif(v){
- returnfalse;
- }else{
- returntrue;
- }
en... 确实,我没有完全验证上面的全面答案的有效性。因为如同龙藏后来强调的:“貌似我们是要讨论什么是烂代码?”的确,我们怎么才能把代码写烂呢?上面出现了种种奇异代码,包括原来提问者的那个取巧的:
[Javascript]view plaincopy- //4.提问者自己的想法
- (a+b+c)%3
因为这个问题出现在js里面,存在弱类型的问题,即a、b、c可能是整数,或字符串等等,因此(a+b+c)%3这个路子就行不通了,所以才有了
[javascript]view plaincopy- //5.云谦对答案4的改进版本
- (!!a+!!b+!!c)%n
2、问题的泛化与求解:普通级别
如果把上面的问题改变一下:
- 如果不是a、b、c三个条件,而是两个以上条件呢?
- 如果强调a、b、c本身不一定是布尔值呢?
那么这个问题的基本抽象就是:
[c-sharp]view plaincopy- //v0,对任意多个运算元求xor
- functione_xor(){...}
- 对于这个e_xor()来说,最直接的代码写法是:
- //v1,扫描所有参数,发现不同的即返回true,全部相同则返回false。
- functione_xor(){
- varargs=arguments,argn=args.length;
- args[0]=!args[0];
- for(vari=1;i<argn;i++){
- if(args[0]!=!args[i])returntrue;
- }
- returnfalse;
- }
接下来,我们考虑一个问题,既然arguments就是一个数组,那么可否使用数组方式呢?事实上,据说在某些js环境中,直接存取arguments[x]的效率是较差的。因此,上面的v1版本可以有一个改版:
[javascript]view plaincopy- //v1.1,对v1的改版
- functione_xor(){
- varargs=[].slice.call(arguments,0),argn=args.length;
- ...
- }
这段小小的代码涉及到splice/slice的使用问题。因为操作的是arguments,因此splice可能导致函数入口的“奇异”变化,在不同的引擎中的表现效果并不一致,而slice则又可能导致多出一倍的数据复制。在这里仍然选用slice()的原因是:这里毕竟只是函数参数,不会是“极大量的”数组,因此无需过度考虑存储问题。
3、问题的泛化与求解:专业级别
接下来,我们既然在args中得到的是一个数组,那么再用for循环就实在不那么摩登了。正确的、流行风格的、不被前端鄙视做法是:
[javascript]view plaincopy- //v2,使用js1.6+的数组方法的实现
- functione_xor(a){
- return([].slice.call(arguments,1)).some(function(b){if(!b!=!a)returntrue});
- }
为了向一些不太了解js1.6+新特性的同学解释v2这个版本,下面的代码分解了上述这个实现:
[javascript]view plaincopy