锁定老帖子 主题:Javascript 函数 (七) 闭包
精华帖 (0) :: 良好帖 (1) :: 新手帖 (10) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-12-26
最后修改:2008-12-26
闭包(Closures)闭包属于比较难的一部分,在学习闭包之前,先来学习以下Javascript的作用域(Scope)作用域链(Scope Chain)函数内部定义的变量,在函数外不能访问,或者变量定义在代码段中(如if,for中),在代码段之外也不可访问。 var a =1; function f(){ var b=1; return a; } f();//a=1 b;//b 没有定义 a 是全局变量,而b定义在函数f之中。所以: 在f函数中,a和b都可以访问。 在f函数之外,a可以访问,而b不可以
再次看个例子
var a = 1; function f(){ var b = 1; function n(){ var c =3; } } 如果定义一个函数n在函数f中,函数n不但可以访问自己作用域的c,而且还能访问所谓的父作用域的b和a 这就是作用域链(Scope Chain) 词法作用域(Lexical Scope)在Javascript中,也有词法作用域(Lexical Scope),这个意思是,函数在定义的时候就生成了它的作用域,而不是在调用的时候,看个例子就明白了。 function f1(){var a=1;f2();} function f2(){return a;} f1();//a没有定义 先看看函数f1,调用了函数f2,因为函数局部变量a也在f1中,可能期望函数f2也访问a,但事实却不是这样。 因为这个时候f2函数已经定义完毕了,而它的范围没有a被找到。不管是函数f1还是函数f2,仅仅能访问的是本身的局部变 量或者全局变量。
用闭包来破坏这个作用域链(Breaking the Chain with Closure)让我们举例来说明闭包吧。 实例1 function f(){ var b="b"; return function(){ return b; } } 函数f包含了变量b,在全局作用域中不可能访问b,结果为没有定义(undefined)。 看看这个函数的返回值为一个函数。这个新的函数可以访问f范围中的变量b。看如下代码
var n = f(); n();//访问b 由于函数f本身就是全局的,而它返回的函数又是个新的全局函数,而它又可以访问函数f的作用域。
实例2 这个例子和上个例子结果是一样的,但是有一点不同,函数f并不返回一个函数,而是新建一个全局变量n,代码如下 var n; function f(){ var b = "b"; n=function(){ return b; } } 所以可以直接n()来访问函数f里的变量b
通过上面两个例子我们就可以说当一个函数指向了它的父作用域,就可以称之为闭包。 当我们创建了个传递参数的函数f,这个参数就变成了函数f的局部变量了。我们可以创建一个f的内部函数来返回这个参数 function f(arg){ var n =function(){ return args; } arg++; return n; } var m= f(123); m();//124
闭包在循环中的应用再循环中很容易引起一些bug,虽然表面是正常的。 看如下的代码 function f(){ var a = []; var i; for(i=0;i<3;i++){ a[i] = function(){ alert(i); return i; } } return a; } var a= f(); a[0]();//3 a[1]();//3 a[2]();//3 新建个循环,我们的目的是每次循环都新建一个函数,函数返回的是循环的序列值也就是i。我们看看以上代码的运行结果 都是为3.而我们期望的结果是1,2,3。 到底是为什么呢?我们新建了三个闭包,都指向了变量i。闭包并没有记住变量i的值,它仅是变量i的引用。在循环结束后,i的值是3,所以结果都是3了。
来看看正确的写法 function f() { var a = []; var i; for(i = 0; i < 3; i++) { a[i] = (function(x){ return function(){ alert(x); return x; } })(i); } return a; } var a = f(); a[0]();//0 a[1]();//1 a[2]();//2 我们又用了一个闭包,把变量i变成了局部变量x了,x变量每次都是不同的值了。如果没有彻底理解自调用函数那就如下写法就可以明白了 function f() { function makeClosure(x) { return function(){ return x; } } var a = []; var i; for(i = 0; i < 3; i++) { a[i] = makeClosure(i); } return a; }
|
|
返回顶楼 | |
发表时间:2009-06-01
翻译得不错.
|
|
返回顶楼 | |
发表时间:2009-08-01
"或者变量定义在代码段中(如if,for中),在代码段之外也不可访问"
lz,上面这句话有点问题,建议修改一下,javascript中有c系语言的code block structure,但是没有block scope, 在函数中用var声明的变量时function scope的。 function testScope(){ if(true){ var inner = "hello"; } alert(inner); } |
|
返回顶楼 | |
浏览 3746 次