您的位置:首页 > Web前端 > JavaScript

Javascript学习笔记四 之 闭包

2010-12-18 14:21 183 查看
参考整理:http://www.cnblogs.com/zhangle/archive/2010/07/02/1770206.html

[b]1.什么是闭包[/b]



之前讲过内部函数(Inner Function),在outer函数的外部是无法访问inner函数的。所以也称之为私有函数(private function);

但是在很多情况下,我们需要访问到内部的作用域。这个时候就需要闭包。

function f(){
var b="b";
return function(){
return b;
};
}

alert(f());


alert的结果是

function(){

  return b;

}


因为返回了一个匿名函数,由此也说明函数也是数据

为了返回b;我们可以

var n = f();
n();//访问b


我们还可以用下面的方法来替代:

var n;
function f(){
var b = "b";
n=function(){
return b;
}
}
f();
alert(n());


通过上面例子我们就可以说当一个函数指向了它的父作用域,就可以称之为闭包。

官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

闭包的特点:
1.作为一个函数变量的一个引用,当函数返回时,其处于激活状态。
2.一个闭包就是当一个函数返回时,一个没有释放资源的栈区。
简单的说,javascript允许使用内部函数---即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。

官方的解释估计新手没办法一下子看懂,其实闭包简单的说就是:


当函数a的内部变量b(就是数据,可以是对象或函数)被函数a外的一个变量引用的时候,就创建了一个我们通常所谓的“闭包”。


2.闭包的原理

如果要更加深入的了解闭包以及函数a和内部变量b的关系,我们需要引入另外几个概念:函数的执行环境(excution context)、活动对象(call object)、作用域(scope)、作用域链(scope chain)。以函数a从定义到执行的过程为例阐述这几个概念。

定义函数a的时候,js解释器会将函数a的作用域链(scope chain)设置为定义a时a所在的“环境”,如果a是一个全局函数,则scope chain中只有window对象。

执行函数a的时候,a会进入相应的执行环境(excution context)

在创建执行环境的过程中,首先会为a添加一个scope属性,即a的作用域,其值就为第1步中的scope chain。即a.scope=a的作用域链。

然后执行环境会创建一个活动对象(call object)。活动对象也是一个拥有属性的对象,但它不具有原型而且不能通过JavaScript代码直接访问。创建完活动对象后,把活动对象添加到a的作用域链的最顶端。此时a的作用域链包含了两个对象:a的活动对象和window对象。

下一步是在活动对象上添加一个arguments属性,它保存着调用函数a时所传递的参数。

最后把所有函数a的形参和内部变量b的引用也添加到a的活动对象上。在这一步中,完成了b的的定义,因此如同第3步,b的作用域链被设置为b所被定义的环境,即a的作用域。

3.闭包在循环中的应用

在循环中很容易引起一些bug,虽然表面是正常的。

代码

var Class2 = (function(){
var s_var = 0;      //静态私有变量
return function(){
this.getInstanceCount = function(){
return s_var;
}
//constructor
s_var++;
}
})()

var cls1 = new Class2();
alert(cls1.getInstanceCount());   //1

var cls2 = new Class2();
alert(cls1.getInstanceCount());   //2
alert(cls2.getInstanceCount());   //2

var cls3 = new Class2();
alert(cls1.getInstanceCount());   //3
alert(cls3.getInstanceCount());   //3


这个例子中,我们用s_var记录Class2被实例化的次数,使用闭包,我们可以将s_var模拟为一个静态私有变量,每次Class2被实例化的时候将s_var加1。

上例中我们使用了这样形式的一段代码,其中定义在外层函数内,内层函数外的成员类似于静态成员。所以这样形式的代码我们可以把他叫做“静态封装环境”。

(function(){
return function(){
}
})()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: