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);
但是在很多情况下,我们需要访问到内部的作用域。这个时候就需要闭包。
alert的结果是
因为返回了一个匿名函数,由此也说明函数也是数据
为了返回b;我们可以
我们还可以用下面的方法来替代:
通过上面例子我们就可以说当一个函数指向了它的父作用域,就可以称之为闭包。
官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
闭包的特点:
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,虽然表面是正常的。
代码
这个例子中,我们用s_var记录Class2被实例化的次数,使用闭包,我们可以将s_var模拟为一个静态私有变量,每次Class2被实例化的时候将s_var加1。
上例中我们使用了这样形式的一段代码,其中定义在外层函数内,内层函数外的成员类似于静态成员。所以这样形式的代码我们可以把他叫做“静态封装环境”。
[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(){ } })()
相关文章推荐
- JavaScript原型和闭包学习笔记
- Javascript学习笔记:闭包题解(3)
- JavaScript 学习笔记七 闭包
- JavaScript 闭包学习笔记
- JavaScript学习笔记之闭包
- Javascript学习笔记:闭包题解(1)
- JavaScript面向对象学习笔记——闭包
- Javascript学习笔记:闭包题解(4)
- javascript学习笔记(十三) js闭包(转)
- JavaScript学习笔记4-闭包
- JavaScript 学习笔记七 闭包二
- 零基础入门-javascript学习笔记之传说中的闭包
- javascript学习笔记(二)-闭包
- 韩顺平 javascript教学视频_学习笔记16_Object类_闭包_成员函数再说明_聪明的猪小练习
- 《JavaScript高级程序设计 第三版》学习笔记 (六) 函数与闭包详解
- JavaScript学习笔记十四:闭包
- Javascript学习笔记:闭包题解(2)
- Javascript学习笔记3 函数表达式 闭包
- JavaScript学习笔记(6)---闭包