用最通俗易懂的代码帮助新手理解javascript闭包

标签: 代码 帮助 理解 | 发表时间:2012-03-01 01:37 | 作者:hh54188
出处:http://www.cnblogs.com/

我同样也是个javascript新手,怎么说呢,先学的jquery,精通之后发现了javascript的重要性,再回过头来学javascript面向对象编程。

最近看了几篇有关javascript闭包的文章,包括最近正火的 汤姆大叔系列,还有《javascript高级程序设计》中的文章,……我看不懂,里面有些代码是在大学教科书中看都没看过的,天书一般。幸好最近遇到两本好书《ppk on javascript》和《object-oriented JavaScript》,正字阅读中,都还没有中文版,但写的不复杂,有兴趣的朋友可以看看,适合想进阶的朋友。     

今天就结合这两本书,用最浅显的语言和最通俗的方式谈谈javascript中的闭包,因为也是新手,所以有有误的地方请各位指出,谢谢

一.   准备知识

1. 函数作为函数的参数

在学习javascript中,你始终要有一个有学习与其他语言不同的概念:函数(function)不么特殊的东西,它也是一种数据,与bool ,string,number没有什么两样。

函数的参数可以string,number,bool如:

function(a, b) {return a + b;} 

但同样也可以传入函数。对你没有听错,函数的参数是函数!加入你有以下两个函数:

//把三个数翻一倍   
function multiplyByTwo(a, b, c) {
var i, ar = [];

for(i = 0; i < 3; i++) {
ar[i] = arguments[i] * 2;
}
return ar;
}

//把数加一   
function addOne(a) {

return a + 1;

}

然后这么使用

var myarr = [];   

//先把每个数乘以二,用了一个循环

myarr = multiplyByTwo(10, 20, 30);

//再把每个数加一,又用了一个循环

for (var i = 0; i < 3; i++) {myarr[i] = addOne(myarr[i]);}

要注意到其实这个过程用了两个循环,还是有提升的空间的,不如这么做:

function multiplyByTwo(a, b, c, addOne) {   

var i, ar = [];

for(i = 0; i < 3; i++) {

ar[i] = addOne (arguments[i] * 2);

}
return ar;
}

这样就把函数当做参数传递进去了,并且在第一个循环中直接调用。这样的函数就是著名的回调函数(Callback function)

2. 函数作为返回值

在函数中可以有返回值,但是我们一般都熟悉数值的返回,如

function ex(){   

return 12

}

但你一旦意识到函数只是一种数据的话,你就可以想到同样可以返回函数。注意看下面这个函数:

function a() {   

alert('A!');

return function(){

alert('B!');

};

}

它返回了一个弹出”B!”的函数。接下来使用它:

var newFunc = a();   
newFunc();

结果是什么呢?首先执行a()的时候,弹出”A!”,此时newFunc接受了a的返回值,一个函数——此时newFunc就变成了那个被a返回的函数,再执行newFunc时,弹出”B!”

3.javascript 的作用域

javascript的作用域很特别,它是以函数为单位的,而不是像其他语言以块为单位(如一个循环中),看下面这个例子:

var a = 1; function f(){var b = 1; return a;}

如果你此时试图想得到b的值:在firebug中试图输入alert(b)的话,你会得到错误提示:

b is not defined

为什么你可以这么理解:你所在的编程环境或者窗口是最顶级的一个函数,好像一个宇宙,但是b只是在你内部函数的一个变量,宇宙中的小星球上的一个点,你很难找到它,所以在这个环境中你不能调用它的;反之这个内部函数可以调用变量a,因为它暴露在整个宇宙中,无处藏身,同时也可以调用b,因为它就在自己的星球上,函数内部。

就上面这个例子说:

  1. 在f()外,a可见,b不可见
  2. 在f()内,a可见,b也可见

再复杂点:

var a = 1; //b,c在这一层都不可见   

function f(){

var b = 1;

function n() { //a,b,c对这个n函数都可以调用,因为a,b暴露在外,c又是自己内部的

var c = 3;

}

}

问你,函数b可以调用变量c吗?不行,记住javascript的作用域是以函数为单位的,c在n的内部,所以对f来说是不可见的。

开始正式谈闭包:

首先看这个图:

假设G,F,N 分别代表三个层次的函数,层次如图所示,a,b,c分别是其中的变量。根据上面谈到的作用域,我们有如下结论:

  1. 如果你在a点,你是不可以引用b的,因为b对你是不可见的
  2. 只有c可以引用b

闭包的吊诡之处的就在于发生了如下情况:

N突破了F的限制!跑到于a同一层了! 因为函数只认它们在定义时所处的环境而不是执行时,这点很重要),N中的c仍然可以访问b!此时的a还是不可以访问b!

但是这是怎么实现的呢?如下:

闭包1

function f(){   

var b = "b";

return function(){ //没有名字的函数,所以是匿名函数

return b;

}

}

注意返回的函数可以访问它父亲函数中的变量b

此时如果你想取b的值,当然是undefined

但是如果你这么做:

var n = f();   

n();

你可以取到b的值了!虽然此时n函数在f的外面,b又属于f内部的变量,但是f内部出了一个内鬼,返回了b的值……

现在大家有点感觉了吧

闭包2

var n;   

function f(){

var b = "b";

n = function(){

return b;

}

}

如果此时调用f会怎么样?那就生成了一个n的全局范围函数,但是它却能访问f的内部,照样返回b的值,与上面有异曲同工之妙!

闭包3:

你还可以用闭包访问函数的参数

function f(arg) {   

var n = function(){

return arg;

};

arg++;

return n;

}

此时如果使用:

var m = f(123);   

m();

结果是124

因为此时f中返回的匿名函数经过了两道转手,先给n,再赋给外面的m,但本质没有变,把 定义时父函数的参数返回了

闭包4

var getValue, setValue;   

function() {

var secret = 0;

getValue = function(){

return secret;

};

setValue = function(v){

secret = v;

};

})

运行:

getValue()   

0

setValue(123)

getValue()

123



这个就不用解释了吧,如果你有面向对象语言基础的话(如C#),这里的getValue和setValue就类似于一个对象的属性访问器,你可以通过这两个访问器来赋值和取值,而不是能访问其中内容

其实书中还有几个闭包的例子,但是原理用上面四个就足够了,希望能起抛砖引玉的作用,给javascript进阶者对闭包有一个更深刻的理解

本人大四,即将毕业,现寻求一份前端实习工作,简历在这里 下载,包括一份简历和关于自己的网页作品,希望与web前端开发相关,如网页设计,UED,FED。谢谢!

本文链接

相关 [代码 帮助 理解] 推荐:

用最通俗易懂的代码帮助新手理解javascript闭包

- - 博客园_首页
我同样也是个javascript新手,怎么说呢,先学的jquery,精通之后发现了javascript的重要性,再回过头来学javascript面向对象编程. 最近看了几篇有关javascript闭包的文章,包括最近正火的 汤姆大叔系列,还有《javascript高级程序设计》中的文章,……我看不懂,里面有些代码是在大学教科书中看都没看过的,天书一般.

【原创】三把利器快速制作代码帮助文档

- We_Get - 博客园-首页原创精华区
相信不少麻油都已经积累了属于自己的代码库了,不知道是否有过这样的经历:. A:听说你上次写了个通用XXX类库啊,我正好要用到,麻烦把dll发我一下. B:好的,你等一下,我发给你. A:喂,你这个类是怎么用的啊,有没有帮助文档啊. B:汗,没来得及做,我来和你说吧. 一个好用的类库,如果能配上一个好的说明文档(最好还带搜索功能),无疑是为自己和他人提供了莫大的方便,有什么想要的功能,去文档里一查,一目了然.

腾讯云推出云开发低代码平台,帮助小白成为“开发者”

- - IT之家
IT之家11月29日消息 据腾讯云微信公众号消息,腾讯云的小程序云开发已经成为国内最大的 Serverless 开发平台. 同时,腾讯云从今天起,正式推出云开发低代码平台. 据腾讯方面公布数据,目前云开发注册用户数已达 56 万,较去年同期增长 1.5 倍;所服务的开发者超过 100 万;日调用次数超过 7 亿.

互相帮助

- 威 - 杜然的blog——i&#39;m blinded by blackness
每组动作之间,教练让我休息三四十秒钟的时间,说劳逸结合才能增肌增力. 增肌增力,这四个字听着就让人欢喜,觉得付给教练的钱太值了,连休息都能长肌肉长力气. 在这三四十秒的时间里,我跟教练一般会闲聊. 比如,我说如果北京每年都像今年这样多雨,没准儿以后可以北水南调,挖它三条运河,GDP冲得老高了. 有时候,教练会拿出手机中儿子的照片焦灼地等着我的夸赞——我特别理解新爸爸的心情,所以很配合.

怎样帮助他人(转)

- 阿昌 - 时间堂—GTD学习实践小屋
  我们基本上没有什么办法去帮助他人,即使全能的上帝都没有这个能力. 上帝只帮助那些能够自己帮助自己的人:耶稣也曾对人说过:是你们自己坚定的信心在帮助你,不是我. 因为他人的帮助只能解决一时之急,从长远看来,对一个人并没有什么真正的益处.   对于我们任何一个人,生活中总会有一个当下最根本的矛盾问题.

氮磷钾帮助抑制核辐射

- rIPPER - Solidot
提前四月一的超时空章鱼 写道 "核治愈权威Zombies教授的助手Asshole博士经过对日本沿海水质的对比测试,指出预防辐射最好方法是尽量吸收氮磷钾(Amifostine),连日来的实验数据表明一样中国特色小吃富含氮磷钾,但由于氮磷钾挥发性比较强,不能长期曝露在空气中,所以必须采取直接入口的方式吞食.

SignalGuru帮助司机躲开红灯

- hao - Solidot
MIT和普林斯顿大学的研究人员正在研发一套名叫SignalGuru(PDF)的系统,利用安装在仪表盘的智能手机摄像头网络收集的可视化数据,优化驾驶速度,避开路上的红灯,避免等待,同时减少汽油消耗,因为不时的停车和启动是相当耗油的. SignalGuru已在麻省剑桥和新加坡进行了测试. 在剑桥,交通信号灯是根据固定时间表变化的,因此系统可以以三分之二秒的误差预测红灯在何时亮起,能帮助司机平均减少20%的汽油消耗.

"各种电影对你有帮助

- Frankenstein - Cao Liu
1、缺乏学习动力:《幸福终点站》、《风雨哈佛路》. 2、对爱失望:《偷天情缘》、《初恋50次》. 3、自卑失落:《阿甘正传》、《肖申克的救赎》. 4、失败或绝望:《铁权男人》、《迫在眉梢》、《伊丽莎白镇》. 5、厌倦生活:《在世界的转角遇见爱》、《搏击俱乐部》. 《盗梦空间》、《记忆裂痕》、《生死停留》、《死亡幻觉》、《禁闭岛》、《穆赫兰道》、《蝴蝶效应》、《恐怖游轮》、《伤城》、《盗走达芬奇》、《88分钟》、《万能钥匙》、《决胜21点》、《沉默的羔羊》.

BlindSquare:利用 LBS 数据帮助盲人

- - 爱范儿 · Beats of Bits
最近 Foursquare 积累了数量庞大的真实地理位置数据,它拥有 2000 万名用户以及 20 亿次签到. 这些数据不但可以 帮助商户掘金,还可以帮助盲人导航. iOS 应用 BlindSquare 利用 Open Street Maps 来定位用户的位置,然后通过 Foursquare 的数据找出附近有什么地方,再通过苹果内置的 VoiceOver 或 Acapela Group 提供的文本转声音服务,将地名读出来,好让用户知晓,这样便为盲人创建了一个由语音构成的地图.

数据如何帮助业务

- - 小蚊子乐园
文 / 阿里巴巴集团商业智能部资深经理 欧吉良(勾践).        数据的重要性已经被越来越多的公司、个人所熟知与接受,甚至于有过犹不及之势头. 大数据的概念满天飞,似乎一夜之间人人都在谈论大数据,见了面不用 大数据打招呼,好像就不是在数据圈子里混的了. 那么,被外界传得神乎其神的数据,到底可以在哪些方面促进业务的腾飞.