tuy

函数的返回值与函数本身的一些事

昨晚在看《JavaScript语言精粹》的时候,当看到函数那一部分的时候,始终觉得有点难以理解,刹那间感觉智商不够用,代码如下:

var obj =(function(){
var value = 0;
return{
increment:function(inc){
value + = typeof inc == "number"?inc:1;
},
getValue:function(){
return value;
}
}
}())

注意代码最后的一对括号,书中是这样描述的“我们并没有把一个函数赋值给obj,我们是把调用该函数后返回的结果赋值给它,该函数返回一个包含两个方面的对象,并且这些方法继续享有访问value变量的特权”。这段黄色的文字,我是感觉听起来很拗口,不够通俗。其实这样的代码,我们平时主要是用在立即执行的函数里,通过闭包去返回一些内部的私有变量,只是从来没有仔细研究过,如果去掉了最后的一对括号,那么,返回的就是一个函数(对象)了。这个案例的话,我自己调试了下,发现:var obj =fucntion(){}();var obj =(fucntion(){})();这两种写法也都是可以的。
下面我们开始执行上面定义的函数:

obj.increment(1);
alert(obj.getValue());//1
obj.increment(2);
alert(obj.getValue()); //3
alert(typeof obj); //返回结果为object
//如果我们把function后面的一对括号去掉的话,需要先运行obj,才能使用这个对象:
alert(typeof obj); //返回结果为function
obj=obj();          //这是把obj运行完之后再返回给obj
alert(typeof obj); //返回结果为object(因为这时候的obj已经是运行完返回出来的对象了)
obj.increment(1);
alert(obj.getValue());//1
obj.increment(2);
alert(obj.getValue()); //3

看完这个例子似乎,对这里只能用似乎,理解了后面那对括号的作用;但是作者后面举的一个数组的例子,才让深深的体会到,这种写法的好处,函数能把先前的运算结果记录在某个对象里面,即不清空数据,从而避免了大量的重复运算。
//方式1  我们通过普通的递归方式,计算fibonacci()的值:

var totalTimes = 0; var fibonacci = function (n){ totalTimes +=1; return n < 2?n:fibonacci(n-1) + fibonacci(n-2); }
function calculateFibonacci(){
totalTimes = 0;
for(var i =0;i < 11;i++){
document.getElementById("rlt").innerHTML +="//"+i+":"+fibonacci(i)+"
";
}
document.getElementById("rlt").innerHTML+="//totalTimes:"+totalTimes+"
";
}
//方式2 我们通过保存局部变量的方法计算fo()的值:
var fo = function(){
var meno = [0,1];
var fib = function(n){
totalTimes +=1;
var result = meno[n];
if(typeof result != "number"){
result = fib(n-1) + fib(n-2);
meno[n] = result;
}
return result;
};
return fib;
}();
function go(){
totalTimes = 0;
for(var i =0;i<11;i++){
document.getElementById("rlt").innerHTML +="//"+i+":"+fo(i)+"
";
}
document.getElementById("rlt").innerHTML+="//totalTimes:"+totalTimes+"
";
}
document.write("通过普通递归进行运算的结果如下:")
calculateFibonacci()
calculateFibonacci();
document.write("通过保存局部变量的方式进行运算的结果如下:")
go();
go();
//输出结果如下:
通过普通递归进行运算的结果如下:
//0:0
//1:1
//2:1
//3:2
//4:3
//5:5
//6:8
//7:13
//8:21
//9:34
//10:55
//totalTimes:453
//0:0
//1:1
//2:1
//3:2
//4:3
//5:5
//6:8
//7:13
//8:21
//9:34
//10:55
//totalTimes:453
//通过保存局部变量的方式进行运算的结果如下:
//0:0
//1:1
//2:1
//3:2
//4:3
//5:5
//6:8
//7:13
//8:21
//9:34
//10:55
//totalTimes:29
//0:0
//1:1
//2:1
//3:2
//4:3
//5:5
//6:8
//7:13
//8:21
//9:34
//10:55
//totalTimes:11

通过观察结果,第一种方式执行两次,每次都要运算453次才能得出,第二种方式首次执行用了29次,第二次只用了11次,就是最后的数组元素有几个,就只需要运行几次就够了,?是因为每次都要从0,1开始计算,每次算完都清空,周而复始。
第二种方式每次把计算的结果都保存在了meno这个数组中,所以只要计算过一次就被保存下来了,当整个函数执行第二次的时候,因为数组里面每个都被保存了,所以只要挨个return出来就行了,只需要执行数组长度的次数就够了。
当然,我们也可以通过其它方式,如全局变量的形式,将结果保存下来,但是全局变量正是作者极力反对的应用和存储模式之一,而且这个计算结果的保存,本来就是对外透明的,调用它的人需要的只是计算结果,并不需要知道其中如何保存,或者说我们并不需要这个计算函数以外的其它任何(全局)变量,或者任何后来维护这段代码的人,不需要被告知在其它不知道的地方,有计算的中间结果需要他来做多余的维护工作!
当然,我们也可以不用去省掉那400多次计算,不用关心程序的效率,或者不用担心用户的浏览器有多慢!
其实到现在也没有彻底想通,它们之间用处的区别或是优缺点在哪儿,因为始终没想明白说这件事的Point在哪儿,所以,这篇分享文章的标题总觉得没说清楚哈!希望各位同事给予指点!

码字很辛苦,转载请注明来自tuy博客《函数的返回值与函数本身的一些事》

评论

  1. admin
    admin #1

    :cry:

    回复
    2015-06-2