闭包是一个比较抽象的概念,尤其是对js新手来说。在这里,我就我个人的理解j简单谈一下:

闭包:官方解释是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。然而,当我看到这个官方解释的时候顿时就觉得不一般,这个解释太学术了,没达到一定境界的人是理解不了其中深层次内涵的。为此,我们将举出实例来初步说明js中的闭包特性。在了解闭包特性之前,我们需要补充了解变量的作用域。

一、变量的作用域

在JS当中一个变量的作用域(scope)是程序中定义这个变量的区域。变量分为两类:全局(global)变量和局部变量。其中全局变量的作用域是全局性的,即在JavaScript代码中,它处处都有定义。而在函数之内声明的变量,就只在函数体内部有定义。它们是局部变量,作用域是局部性的。函数的参数也是局部变量,它们只在函数体内部有定义。

我们可以借助JavaScript的作用域链(scope chain)更好地了解变量的作用域。每个JavaScript执行环境都有一个和它关联在一起的作用域链。这个作用域链是一个对象列表或对象链。当JavaScript代码需要查询变量x(如下图)的值时(这个过程叫做变量解析(variable name resolution)),它就开始查看该链的第一个对象。如果那个对象有一个名为x的属性,那么就采用那个属性的值。如果第一个对象没有名为x的属性,JavaScript就会继续查询链中的第二个对象。如果第二个对象仍然没有名为x的属性,那么就继续查询下一个对象,以此类推。如果查询到最后(指顶层代码中)不存在这个属性,那么这个变量的值就是未定义的。

例子1:js中的全局变量,结果为50       例子2:js中的局部变量,结果报错,原因就                                                              是函数中的局部变量在外部是不能被引用

     

例子3:看看下面代码,初一看好像结果是50,但是结果确实undefinde,我们来解释说明下为什么是undefind----->

作用域链图中很明确的表示出:在变量解析过程中首先查找局部的作用域,然后查找上层作用域。在例子1中的函数当中没有定义变量i,于是查找上层作用域(全局作用域),进而进行输出其值。但是在例子2中的函数内定义了变量i(无论是在alter之后还是之前定义变量,都认为在此作用域拥有变量i),于是不再向上层的作用域进行查找,直接输出i。然而在例子3中,函数内部依然定义了变量i,于是不会去查找全局作用于,然而不幸的是此时的局部变量i并没有赋值,所以输出的是undefined。

二、闭包的概念

上面官方解释比较学术,我个人比较同意下面这个说法——>即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。也就是说,内部函数会在外部函数返回后被执行。而当这个内部函数执行时,它仍然必需访问其外部函数的局部变量、参数以及其他内部函数。这些局部变量、参数和函数声明(最初时)的值是外部函数返回时的值,但也会受到内部函数的影响。-----个人理解就是:闭包是能够读取其他函数内部变量的函数,即在外面可以调用函数中的函数的变量,其实他就是将函数内外部连接起来的桥梁。

如下面例子4:

这段代码有以下两个特点:

1、函数b嵌套在函数a内部;2、函数a返回函数b;

引用关系如下图:

      这样在执行完var c = a()后,变量c实际上是指向了函数b,b中用到了变量i,再执行c()后就会弹出一个窗口显示i的值(第一次为1)。这段代码其实就创建了一个闭包,为什么?因为函数a外的变量c引用了函数a内的函数b,就是说:

当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个我们通常所谓的“闭包”。

      当函数b执行的时候亦会像以上步骤一样。因此,执行时b的作用域链包含了3个对象:b的活动对象、a的活动对象和window对象,如下图所示:

          

如图所示,当在函数b中访问一个变量的时候,搜索顺序是:

  1. 先搜索自身的活动对象,如果存在则返回,如果不存在将继续搜索函数a的活动对象,依次查找,直到找到为止。
  2. 如果函数b存在prototype原型对象,则在查找完自身的活动对象后先查找自身的原型对象,再继续查找。这就是Javascript中的变量查找机制。
  3. 如果整个作用域链上都无法找到,则返回undefined。

三、闭包的用途及优势

(一)、用途

1、闭包可以读取函数内部变量    2、将函数内部变量的值始终保存在内存中

例子5:

这个例子中的result实际上就是闭包函数b,他一共运行两次,第一次值99,第二次值为100,这就说明i一直在内存中,而不是在第一次a函数调用之后就自动清除。另外还需注意iAdd=function(){i++;},这里iAdd是全局变量,且它的值为匿名函数,其实也是一个闭包。

(二)、优势

1、保护函数内的变量安全。以最开始的例子为例,函数a中i只有函数b才能访问,而无法通过其他途径访问到,因此保护了i的安全性。

 2、在内存中维持一个变量。依然如前例,由于闭包,函数a中i的一直存在于内存中,因此每次执行c(),都会给i自加1。

 3、通过保护变量的安全实现JS私有属性和私有方法(不能被外部访问)。

原文地址:http://my.oschina.net/longteng2013/blog/156782

最新文章

  1. [LeetCode] Create Maximum Number 创建最大数
  2. Hadoop学习笔记—15.HBase框架学习(基础实践篇)
  3. Linux网络编程(简单的时间获取服务器)
  4. 跨平台开发之阿里Weex框架环境搭建(一)
  5. jquery实现轮播图
  6. luogu1151 亲戚
  7. 如何彻底的卸载sql server数据库
  8. iOS 进阶 第七天(0403)
  9. Qt入门(13)——Qt的调用退出
  10. DayOfWeek中英文星期转换
  11. FPGA STA(静态时序分析)
  12. 198,House Robber
  13. string 至 Color 转换演示示例:
  14. Linux中iptables设置详细
  15. 关于自己封装Web前端框架的思考和探索
  16. uva11991 Easy Problem from Rujia Liu?
  17. redis五种基本类型CRUD操作
  18. vue.js设置、获取、删除cookie
  19. Mocha+should+Karma自动化测试教程
  20. div中的相对定位与绝对定位

热门文章

  1. 彩色图像--色彩空间 CMY(K)场地
  2. CentOS7 安装zookeeper
  3. u_boot启动过程中的具体分析(1)
  4. ios7 JavaScriptCore.framework
  5. ABP领域层——工作单元(Unit Of work)
  6. jsp 说明标签
  7. malloc,free简单的实现
  8. 初学git && 使用总结
  9. libmsgque官方主页
  10. hdu 4831 Scenic Popularity(模拟)