闭包是一个比较抽象的概念,尤其是对js新手来说.书上的解释实在是比较晦涩,对我来说也是一样.

  但是他也是js能力提升中无法绕过的一环,几乎每次面试必问的问题,因为在回答的时候.你的答案的深度,对术语的理解以及js内部解释器的运作方式的描述,都是可以看出你js实际水平的.即使你没答对,也能让考官对你的水平有个评估.那么我先来说说我对js中的闭包的理解.

  闭包是很多语言都具备的特性,在js中,闭包主要涉及到js的几个其他的特性:作用域链,垃圾(内存)回收机制,函数嵌套,等等.

  在理解闭包以前.最好能先理解一下作用域链的含义,简单来说,作用域链就是函数在定义的时候创建的,用于寻找使用到的变量的值的一个索引,而他内部的规则是,把函数自身的本地变量放在最前面,把自身的父级函数中的变量放在其次,把再高一级函数中的变量放在更后面,以此类推直至全局对象为止.当函数中需要查询一个变量的值的时候,js解释器会去作用域链去查找,从最前面的本地变量中先找,如果没有找到对应的变量,则到下一级的链上找,一旦找到了变量,则不再继续.如果找到最后也没找到需要的变量,则解释器返回undefined.

  了解了作用域链,我们再来看看js的内存回收机制,一般来说,一个函数在执行开始的时候,会给其中定义的变量划分内存空间保存,以备后面的语句所用,等到函数执行完毕返回了,这些变量就被认为是无用的了.对应的内存空间也就被回收了.下次再执行此函数的时候,所有的变量又回到最初的状态,重新赋值使用.但是如果这个函数内部又嵌套了另一个函数,而这个函数是有可能在外部被调用到的.并且这个内部函数又使用了外部函数的某些变量的话.这种内存回收机制就会出现问题.如果在外部函数返回后,又直接调用了内部函数,那么内部函数就无法读取到他所需要的外部函数中变量的值了.所以js解释器在遇到函数定义的时候,会自动把函数和他可能使用的变量(包括本地变量和父级和祖先级函数的变量(自由变量))一起保存起来.也就是构建一个闭包,这些变量将不会被内存回收器所回收,只有当内部的函数不可能被调用以后(例如被删除了,或者没有了指针),才会销毁这个闭包,而没有任何一个闭包引用的变量才会被下一次内存回收启动时所回收.

也就是说,有了闭包,嵌套的函数结构才可以运作,这也是符合我们的预期的.然后,闭包还有一些特性,却往往让程序员觉得很难理解.

看看下面一段代码.

var result=[];
function foo(){
var i= 0;
for (;i<3;i=i+1){
result[i]=function(){
alert(i)
}
}
};
foo();
result[0](); //
result[1](); //
result[2](); //

这段代码中,程序员希望foo函数中的变量i被内部循环的函数使用,并且能分别获得他们的索引,而实际上,只能获得该变量最后保留的值,也就是说.闭包中所记录的自由变量,只是对这个变量的一个引用,而非变量的值,当这个变量被改变了,闭包里获取到的变量值,也会被改变.

解决的方法之一,是让内部函数在循环创建的时候立即执行,并且捕捉当前的索引值,然后记录在自己的一个本地变量里.然后利用返回函数的方法,重写内部函数,让下一次调用的时候,返回本地变量的值,改进后的代码:

var result=[];
function foo(){
var i= 0;
for (;i<3;i=i+1){
result[i]=(function(j){
return function(){
alert(j);
};
})(i);
}
};
foo();
result[0](); //
result[1](); //
result[2](); //

在这里我再解释一下.这里用到了另外2个技术,立即调用的匿名函数和返回函数.也是初学者比较难以理解的部分.

转自

:http://www.cnblogs.com/mzwr1982/archive/2012/05/20/2509295.html

js中的闭包理解一的更多相关文章

  1. js中的闭包理解

    闭包是一个比较抽象的概念,尤其是对js新手来说.书上的解释实在是比较晦涩,对我来说也是一样. 但是他也是js能力提升中无法绕过的一环,几乎每次面试必问的问题,因为在回答的时候.你的答案的深度,对术语的 ...

  2. js中的闭包之我理解

    闭包是一个比较抽象的概念,尤其是对js新手来说.书上的解释实在是比较晦涩,对我来说也是一样. 但是他也是js能力提升中无法绕过的一环,几乎每次面试必问的问题,因为在回答的时候.你的答案的深度,对术语的 ...

  3. 详解js中的闭包

    前言 在js中,闭包是一个很重要又相当不容易完全理解的要点,网上关于讲解闭包的文章非常多,但是并不是非常容易读懂,在这里以<javascript高级程序设计>里面的理论为基础.用拆分的方式 ...

  4. 浅谈JS中的闭包

    浅谈JS中的闭包 在介绍闭包之前,我先介绍点JS的基础知识,下面的基础知识会充分的帮助你理解闭包.那么接下来先看下变量的作用域. 变量的作用域 变量共有两种,一种为全局变量,一种为局部变量.那么全局变 ...

  5. JavaScript中的闭包理解

    原创文章,转载请注明:JavaScript中的闭包理解  By Lucio.Yang 1.JavaScript闭包 在小学期开发项目的时候,用node.js开发了服务器,过程中遇到了node.js的第 ...

  6. js中的“闭包”

    js中的“闭包” 姓名:闭包 官方概念:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. ( ⊙o⊙ )!!!这个也太尼玛官方了撒,作为菜鸟的 ...

  7. JS中的闭包(closure)

    JS中的闭包(closure) 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现.下面就是我的学习笔记,对于Javascript初学者应该是很有用 ...

  8. Js中的闭包原理

    要了解清楚js中的闭包制机,那么得先了解全局执行环境.块级执行环境.函数执行环境.变量对象.环境栈.作用域链.摧毁执行环境. 全局执行环境 全局执行环境指的是最外层的执行环境.在web中全局执行环境被 ...

  9. 理解js中的闭包

    闭包 我的理解是 能够有权访问另一个函数作用域中变量的函数 通常我们知道 普通的函数在调用完成之后,活动对象不会从内存中销毁,其执行环境的作用域链会被销毁,造成资源的浪费 而闭包的好处就在于执行完就会 ...

随机推荐

  1. solr&lucene3.6.0源码解析(二)

    上文描述了solr3.6.0怎么采用maven管理的方式在eclipse中搭建开发环境,在solr中,为了提高搜索性能,采用了缓存机制,这里描述的是LRU缓存,这里用到了 LinkedHashMap类 ...

  2. jeecms栏目模型和内容模型的使用以及对应前台的标签中的属性名

    第一步:模型管理-添加模型: 栏目模板前缀设定方案下的channel目录下的ch_menu.html作为浏览栏目的模板页.对应访问网址:项目名/栏目名(一级或者二级栏目如news或者gnxw)/ind ...

  3. 一些linux工具在windows版本下的文件放置位置

    首先说明一下windows下的常用变量(这里是XP的,win7及以上的C:\Documents and Settings实际为C:\Users) %SystemDrive%        操作系统所在 ...

  4. php数组倒叙支持多维数组

    <?php //一维数组 $test1 = array("a"=>"苹果","b"=>"香蕉",&qu ...

  5. ZKEACMS 2.2.1 正式发布,更多特性等您来发现

    前言 如果你还不知道ZKEACMS,不妨先了解一下. ASP.NET MVC 开源建站系统 ZKEACMS 推荐,从此网站“拼”起来 官方地址:http://www.zkea.net/zkeacms ...

  6. AutoCompleteTextView 和 MultiAutoCompleteTextView 自动完成文本控件

    概述 在html中有很多自动完成的应用,例如,百度的搜索,输入一些关键字,下面就会自动列出该关键字对应的一些消息 在Android中也有自动完成文本,这就是AutoCompleteTextVeiw和M ...

  7. Linux Shell 编程学习笔记

    1:Shell Script中if语句的条件部分要以分号来分隔 2:要注意条件测试部分中的空格.在方括号的两侧都有空格 3:echo "Hi, ${a}s" 单引号中的变量不会进行 ...

  8. dataframe去重 drop_duplicates

    data.drop_duplicates() #默认:data中一行元素全部相同时才去除 data.drop_duplicates(['a','b'])#data根据’a','b'组合列删除重复项,默 ...

  9. jQuery如何追加内容?匿名函数

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. 获取请求 header 中指定字段的值

    private function getHeader($name) {//获取请求头中$name的值 $name = 'HTTP_' . $name; foreach ($_SERVER as $ke ...