今天在读《JavaScript语言精粹》的时候,关于函数的一个部分,始终觉得有点难以理解,代码如下:

   1: var obj = (function(){

   2:     var value = 0;

   3:     

   4:     return {

   5:         increment:function(inc){

   6:             value += typeof inc == "number"?inc:1;

   7:         },

   8:         getValue:function(){

   9:             return value;

  10:         }

  11:     };

  12: }());

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

注意代码最后的标黄色的一对括号,书中是这样描述的“我们并没有把一个函数赋值给obj,我们是把调用该函数后返回的结果赋值给它,该函数返回一个包含两个方面的对象,并且这些方法继续享有访问value变量的特权”。其实像这样代码,用的也比较多,只是从来没有仔细琢磨过,如果去掉了最后的一对括号,那么,返回的就是一个函数(对象)了。

如果我们在代码中这样调用上面的obj,则可以直接使用,执行typeof obj 返回结果为”object”,如:

   1: obj.increment(1);

   2: alert(obj.getValue());//1

   3: obj.increment(2);

   4: alert(obj.getValue());//3

如果去掉最后的一对括号,执行typeof obj 返回结果为“function”,需要使用先声明初始化的方式,才能使用这个对象,如:

   1: var o = obj();

   2: o.increment(1);

   3: alert(o.getValue());//1

   4: o.increment(2);

   5: alert(o.getValue());//3

这样似乎理解了有没有那对括号的区别。但是作者后面举的Fibonacci例子,才让我恍然大悟,原来它还有这么个好的用处。即,函数可以将先前的操作结果记录在某个对象里,从而避免无谓的重复运算。

我们通过普通的递归方式,计算Fibonacci数值,代码如下:

   1: var totalTimes = 0;

   2:  

   3: var fibonacci = function (n){

   4:     totalTimes +=1;

   5:     return n<2?n:fibonacci(n-1) + fibonacci(n-2);

   6: }

   7:  

   8: function calculateFibonacci(){

   9:     totalTimes = 0;

  10:     for(var i =0;i<11;i++){

  11:         document.getElementById("rlt").innerHTML +="//"+i+":"+fibonacci(i)+"<br/>";

  12:     }

  13:     document.getElementById("rlt").innerHTML+="//totalTimes:"+totalTimes+"<br/>";

  14: }

连续执行两次,我们会看到如下的结果:

   1: //0:0

   2: //1:1

   3: //2:1

   4: //3:2

   5: //4:3

   6: //5:5

   7: //6:8

   8: //7:13

   9: //8:21

  10: //9:34

  11: //10:55

  12: //totalTimes:453

  13: //0:0

  14: //1:1

  15: //2:1

  16: //3:2

  17: //4:3

  18: //5:5

  19: //6:8

  20: //7:13

  21: //8:21

  22: //9:34

  23: //10:55

  24: //totalTimes:453

是的,两次都是执行了453次。因为每次都要重新从0,1开始计算。

但是,如果我们使用了如下代码(注意它最后的一对括号):

   1: var totalTimes = 0;

   2: var fibonacciMemo = function(){

   3:     var meno = [0,1];

   4:     var fib = function(n){

   5:         totalTimes +=1;

   6:         var result = meno[n];

   7:         if(typeof result != "number"){

   8:             result = fib(n-1) + fib(n-2);

   9:             meno[n] = result;

  10:         }

  11:         return result;

  12:         

  13:     };

  14:     return fib;

  15: }();

  16:  

  17: function calculateFibonacciEx()

  18: {

  19:     totalTimes = 0;

  20:     for(var i =0;i<11;i++){

  21:         document.getElementById("rlt").innerHTML +="//"+i+":"+fibonacciMemo(i)+"<br/>";

  22:     }

  23:     document.getElementById("rlt").innerHTML+="//totalTimes:"+totalTimes+"<br/>";

  24: }

连续执行两次,我们看到的结果却是这样:

   1: //0:0

   2: //1:1

   3: //2:1

   4: //3:2

   5: //4:3

   6: //5:5

   7: //6:8

   8: //7:13

   9: //8:21

  10: //9:34

  11: //10:55

  12: //totalTimes:29

  13: //0:0

  14: //1:1

  15: //2:1

  16: //3:2

  17: //4:3

  18: //5:5

  19: //6:8

  20: //7:13

  21: //8:21

  22: //9:34

  23: //10:55

  24: //totalTimes:11

是的,第一次执行了29次计算,第二次只执行了11次计算。原因在于我们把结果保存在了meno这个数组中。

当然,我们也可以通过其它方式,如全局变量的形式,将结果保存下来,但是全局变量正是作者极力反对的应用和存储模式之一,而且这个计算结果的保存,本来就是对外透明的,调用它的人需要的只是计算结果,并不需要知道其中如何保存,或者说我们并不需要这个计算函数以外的其它任何(全局)变量,或者任何后来维护这段代码的人,不需要被告知在其它不知道的地方,有计算的中间结果需要他来做多余的维护工作!

当然,我们也可以不用去省掉那400多次计算,不用关心程序的效率,或者不用担心用户的浏览器有多慢!

其实到现在也没有相通,它们之间用处的区别或是优缺点在哪儿,因为始终没想明白说这件事的Point在哪儿,所以,博文的标题总觉得没说清楚哈!希望大家给予指点!

JavaScript中对象与函数的某些事[JavaScript语言精粹-N1]的更多相关文章

  1. 前端学习 第二弹: JavaScript中的一些函数与对象(1)

    前端学习 第二弹: JavaScript中的一些函数与对象(1) 1.apply与call函数 每个函数都包含两个非继承而来的方法:apply()和call(). 他们的用途相同,都是在特定的作用域中 ...

  2. javascript中对象字面量的理解

    javascript中对象字面量与数组字面量 第一部分 我们知道JavaScript中的数据类型有基本数据类型和引用类型,其中Object类型就是非常常用的类型.那么如果创建一个Object类型的实例 ...

  3. 理解和使用 JavaScript 中的回调函数

    理解和使用 JavaScript 中的回调函数 标签: 回调函数指针js 2014-11-25 01:20 11506人阅读 评论(4) 收藏 举报  分类: JavaScript(4)    目录( ...

  4. 关于JavaScript中对象的继承实现的学习总结

    一.原型链 JavaScript 中原型链是实现继承的主要方法.其主要的思想是利用原型让一个引用类型继承另一个引用类型的属性和方法.实现原型链有一种基本模式,其代码如下. function Super ...

  5. javascript中对象的深度克隆

    记录一个常见的面试题,javascript中对象的深度克隆,转载自:http://www.2cto.com/kf/201409/332955.html 今天就聊一下一个常见的笔试.面试题,js中对象的 ...

  6. [原创]javascript prototype 对象 函数 <精简的美丽......>

    精简的美丽...... javascript prototype 对象 函数 在javascript中我们都知道创建一个对象使用如下代码var x = {}对象可以拥有属性和方法var x = {   ...

  7. 在 JavaScript 中使用构造器函数模拟类

    今天,我们要讲的是在 JavaScript 中使用构造器函数(construcor function)模拟类. 构造器函数简介 你可以使用 ES6 的 class 关键字来实现类,不过我建议你使用传统 ...

  8. 来一轮带注释的demo,彻底搞懂javascript中的replace函数

    javascript这门语言一直就像一位带着面纱的美女,总是看不清,摸不透,一直专注服务器端,也从来没有特别重视过,直到最近几年,javascript越来越重要,越来越通用.最近和前端走的比较近,借此 ...

  9. 理解javascript中的回调函数(callback)【转】

    在JavaScrip中,function是内置的类对象,也就是说它是一种类型的对象,可以和其它String.Array.Number.Object类的对象一样用于内置对象的管理.因为function实 ...

随机推荐

  1. 校园社交网站app

    1.项目说明 1.1 项目背景 虽然公共社交网络系统能够满足大多数高校校园用户在校园网络社交的需求,但是针对校园学习.工作和文化生活等方面的支持以及学校个性化需求方面却存在不足.利用电子校务平台的数据 ...

  2. ELK 性能(1) — Logstash 性能及其替代方案

    ELK 性能(1) - Logstash 性能及其替代方案 介绍 当谈及集中日志到 Elasticsearch 时,首先想到的日志传输(log shipper)就是 Logstash.开发者听说过它, ...

  3. [Asp.net MVC]Asp.net MVC5系列——布局视图

    目录 系列文章 概述 布局视图 系列文章 [Asp.net MVC]Asp.net MVC5系列——第一个项目 [Asp.net MVC]Asp.net MVC5系列——添加视图 [Asp.net M ...

  4. 【JavaService】使用Java编写部署windows服务

    如果你玩windows系统,你对服务这个东西并不会陌生,服务可以帮我们做很多事情,在不影响用户正常工作的情况下,可以完成很多我们需要的需求. 众所周知,微软的visio studio内置的Servic ...

  5. CUDA ---- GPU架构(Fermi、Kepler)

    GPU架构 SM(Streaming Multiprocessors)是GPU架构中非常重要的部分,GPU硬件的并行性就是由SM决定的. 以Fermi架构为例,其包含以下主要组成部分: CUDA co ...

  6. ubuntu14.04如何设置静态IP的方法

    第一步: 配置静态IP地址: 打开/etc/network/interfaces文件,内容为 auto lo iface lo inet loopback auto eth0 iface eth0 i ...

  7. ubuntu修改用户名并修改home对应的目录名

    1.新建一个新的用户user2 sudo adduser temporary sudo adduser temporary sudo 2.从user1 logout.进入新建用户user2,修改use ...

  8. Oil Skimming HDU - 4185(匹配板题)

    Oil Skimming Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tota ...

  9. 浅谈平衡树splay

    首先splay和treap不一样,treap通过随机数来调整树的形态.但splay不一样,再每插入或操作一次后,你都会把他旋转到根,再旋转过程中树的形态会不断改变,这样来达到均摊效果 常数据大. 来看 ...

  10. CF1025D Recovering BST

    题意:给定序列,问能否将其构成一颗BST,使得所有gcd(x, fa[x]) > 1 解:看起来是区间DP但是普通的f[l][r]表示不了根,f[l][r][root]又是n4的会超时,怎么办? ...