ecmascript最让人误解的一点是他支持闭包。所谓闭包,是指词法表示包括不必计算的变量的函数。也就是说,该函数能使用函数外定义的变量。在ecmascript中使用全局变量时一个简单的闭包实例:
var sMessage="hello world";
function sayHelloWorld(){
alert(sMessage);
}
sayhelloworld();
会输出helloworld。
在一个函数中定义另外一个函数会使闭包更复杂。
var iBaseNum=10; function addNumbers(iNum1,iNum2){ function doAddition(){ return iNum1+iNum2+iBaseNum; } return doAddtion(); }
这里,函数addNumbers()包括函数doAddtion()(闭包),内部函数是个闭包,因为它将获取外部函数的参数inum1,inum2和全局变量ibaseNum的值。addNUmber()最后一步调用了内部函数,这里要掌握的重要概念是doAddtion()函数根本不接受参数,它使用的值是从执行环境中获取的。
另一篇文章:http://www.cnblogs.com/hh54188/archive/2012/03/01/2374921.html
函数作为返回值
在函数中可以有返回值,但是我们一般都熟悉数值的返回,但你一旦意识到函数只是一种数据的话,你就可以想到同样可以返回函数。注意看下面这个函数:
function a() { alert('A!'); return function(){ alert('B!'); }; }
它返回了一个弹出”B!”的函数。接下来使用它:
var newFunc = a(); newFunc();
结果是什么呢?首先执行a()的时候,弹出”A!”,此时newFunc接受了a的返回值,一个函数——此时newFunc就变成了那个被a返回的函数,再执行newFunc时,弹出”B!”
avascript的作用域
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来说是不可见的。
开始正式谈闭包:
首先看这个图:
假设G,F,N 分别代表三个层次的函数,层次如图所示,a,b,c分别是其中的变量。根据上面谈到的作用域,我们有如下结论:
- 如果你在a点,你是不可以引用b的,因为b对你是不可见的
- 只有c可以引用b
闭包的吊诡之处的就在于发生了如下情况:
N突破了F的限制!跑到于a同一层了!因为函数只认它们在定义时所处的环境(而不是执行时,这点很重要),N中的c仍然可以访问b!此时的a还是不可以访问b!
但是这是怎么实现的呢?如下:
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
这里的getValue和setValue就类似于一个对象的属性访问器 来自;http://www.cnblogs.com/hh54188/archive/2012/03/01/2374921.html
http://www.cnblogs.com/TomXu/archive/2012/01/31/2330252.html