闲耘.博客

巨人归来。

前段时间不记得在哪里看到的说法:Javascript全等于(===)比普通等于(==)效率低,我当时在没有测试的情况下就隐约相信了这样的提法,因为初步想来,要多一个等号字符,要同时比较类型和值,效率低一点不是没有道理的。有了这种想法,就时时顾虑着我之前偏向于使用“强类型”的完全等于比较符是否于我不利。

今天一位同事看我代码时“抱怨”我用的完全等于太多了,并随口问了句“三个等号效率要高一些吗?”兴许说者无心,但是听着有意,在Editplus里随手写了几行测试代码,却发现结果与前文提到的说法完全相反:

var I=400000;
var d1 = new Date();
for (var i=0; i<I; i++){
 1==”1″;
}
d1 = new Date()-d1;

var d2 = new Date();
for (var i=0; i<I; i++){
 1===”1″;
}
d2 = new Date()-d2;

document.write(d1+”:”+d2);

测试结果是完全等于(===)效率要高于普通等于(==),我猜想造成这样的结果缘由如下:完全等于不进行类型转换,但是普通等于需要进行类型转换(Javascript是弱类型、但不是无类型)。

注:这里使用了两个类型不同的对象/值进行比较,如果换成同类型对象/值进行比较(如:1==1/1===1)则效率相当。

关于使用等于/完全等于的建议:
1. 如果程序对“强”类型不作要求,或者看重代码量(虽然我认为多加几个等号代码也多不到哪里去),则建议使用等于(==);
2. 否则建议使用完全等于(===)。

我过多使用完全等于号即考虑类型匹配性,如果不匹配,快速失败。

今天看了dennis的《用递归计算阶乘咋不行呢?》受益良多,这里做下小结。

传统的递归算法写起来很漂亮,代码很简洁,但是没递归一次就需要更深一层的堆栈支持,可能会造成内存溢出而失败,所以递归和goto语句一样声名狼藉。

甚至《代码大全》的作者有这样一句话:如果为我工作的程序员用递归去计算阶乘,那么我宁愿换人。作者对递归的态度相当谨慎,这在静态命令式语言中显然是正确的,但是在函数式语言中,由于有尾递归优化的存在,递归反而是最自然的形式,况且我打心里认为递归更符合人类思维。(by dennis)


尾递归就是从最后开始计算,每递归一次就算出相应的结果,也就是说,函数调用出现在调用者函数的尾部,因为是尾部,所以根本没有必要去保存任何局部变量,直接让被调用的函数返回时越过调用者,返回到调用者的调用者去。举例说明。
线性递归(传统递归方式):

function recursion(n){
    return n==1?1:n*recursion(n-1);
}

尾递归:

function tailRecursion(n, a){
    a = a||1; // 尾递归之尾,即上次递归结果。
    return n==1?a:tailRecursion(n-1, a*n);
}



这里将基于尾递归的求数值阶乘算法贴下:

Math.factorial_III = function(n){
    var a = arguments[1]||1;
    return n<=1?a:Math.factorial_III(n-1, a*n);
};

效率上和循环迭代、阶乘改进算法相当甚至稍胜出(ie6,firefox2,safari3),普通递归的效率最为底下,且需要深入堆栈。

参考:
尾递归》-百度百科
用递归计算阶乘咋不行呢?》-dennis

群里一个朋友开发时需要封闭,这是他们的聊天记录片段:

Ray(317058699)  9:35:30
封闭还未归?
aspirin(71446375)  9:35:38
早回来了
aspirin(71446375)  9:35:46
刑期已满
Ray(317058699)  9:36:09
呵呵,以后不要干坏事了哦,
IaiJava(282705730)  9:36:11
犯了什么罪?
Ray(317058699)  9:36:26
当了程序员。。