用最通俗易懂的代码帮助新手理解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,因为它就在自己的星球上,函数内部。
就上面这个例子说:
在f()外,a可见,b不可见
在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来说是不可见的。

开始正式谈闭包:

首先看这个图:

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

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

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

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

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

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wdjgyd.html