闭包是一个比较抽象的概念,尤其是对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

JavaScript的闭包特性的更多相关文章

  1. 深入理解JavaScript的闭包特性如何给循环中的对象添加事件

    初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...

  2. 如何给循环中的对象添加事件--深入理解JavaScript的闭包特性

    初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...

  3. 深入理解JavaScript的闭包特性 如何给循环中的对象添加事件(转载)

    原文参考:http://blog.csdn.net/gaoshanwudi/article/details/7355794 初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数 ...

  4. JavaScript的闭包特性如何给循环中的对象添加事件(一)

    初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...

  5. Javascript中闭包的个人理解

       Javascript的一个特殊点就在于它的闭包和回调特性,这两个特性让初学Javascript的我是云里雾里,至今仍在苦苦摸索与理解.在一番苦思之后,整理了一下资料,将自己的理解思路记录下来,以 ...

  6. javascript进阶——面向对象特性

    面向对象的javascript是这门语言被设计出来时就考虑的问题,熟悉OOP编程的概念后,学习不同的语言都会发现不同语言的实现是不同的,javascript的面向对象特性与其他具有面向对象特性的语言的 ...

  7. javascript 关于闭包的知识点

    javascript 关于闭包的认识 概念:闭包(closure)是函数对象与变量作用域链在某种形式上的关联,是一种对变量的获取机制. 所以要大致搞清三个东西:函数对象(function object ...

  8. Javascript中闭包的作用域链

    作用域定义了在当前上下文中能够被访问到的成员,在Javascript中分为全局作用域和函数作用域,通过函数嵌套可以实现嵌套作用域. 闭包一般发生在嵌套作用域中.闭包是JavaScript最强大的特性之 ...

  9. 从匿名函数(闭包特性)到 PHP 设计模式之容器模式

    匿名函数(匿名函数) 匿名函数,也叫闭包函数,它允许临时创建一个没有指定名称的函数,常用作回调函数参数的值,也可以作为变量的值来使用.具体的使用见以下示例代码: /* 示例一:声明一个简单匿名函数,并 ...

随机推荐

  1. cocos2d-x3.0 windows 环境配置

    cocos2d-x3.0 windows 环境配置 参考Oo泡泡糖oO的CSDN博文 :http://blog.csdn.net/u010296979/article/details/24273393 ...

  2. hexo 部署至Git遇到的坑

    查找资料的时候发现了next这个博客主题,next!非常的漂亮,顺手查看了hexo的相关部署. Hexo官方介绍 Hexo 是一个快速.简洁且高效的博客框架.Hexo 使用 Markdown(或其他渲 ...

  3. Linux内核分析(六)----字符设备控制方法实现|揭秘系统调用本质

    原文:Linux内核分析(六)----字符设备控制方法实现|揭秘系统调用本质 Linux内核分析(六) 昨天我们对字符设备进行了初步的了解,并且实现了简单的字符设备驱动,今天我们继续对字符设备的某些方 ...

  4. React组件开发入门

    React 组件开发入门 Introduction 本文组成: Ryan Clark文章Getting started with React的翻译. 博主的实践心得. React由Facebook的程 ...

  5. getBoundingClientRect的用法

    getBoundingClientRect用于获取某个元素相对于视窗的位置集合.集合中有top, right, bottom, left等属性. 1.语法:这个方法没有参数. rectObject = ...

  6. Caused by: java.lang.ClassNotFoundException: javax.transaction.TransactionManager

    1.错误叙述性说明 usage: java org.apache.catalina.startup.Catalina [ -config {pathname} ] [ -nonaming ] { -h ...

  7. oracle----sqlldr用法(转)

    SQL*LOADER是ORACLE的数据加载工具,通常用来将操作系统文件迁移到ORACLE数据库中.SQL*LOADER是大型数据仓库选择使用的加载方法,因为它提供了最快速的途径(DIRECT,PAR ...

  8. quick-cocos2d-x游戏开发【6】——制作您自己的自定义效果button菜单

    前面提到的主菜单使用,还是很easy的,但我们在商业产品.经常看到button他们人很好,照片不仅就好了,和动画也很不错.Candy Crash都玩过吧,他们看到,button.真的像果冻,效果确实非 ...

  9. projecteuler---->problem=34----Digit factorials

    Problem 34 145 is a curious number, as 1! + 4! + 5! = 1 + 24 + 120 = 145. Find the sum of all number ...

  10. UI測试内容

    我们在实际工作其中,针对web应用程序,也就是常常所说的B/S系统,能够从例如以下方面来进行用户界面測试: 导航測试 导航描写叙述了用户在一个页面内操作的方式,在不同的用户接口控制之间,比如butto ...