闭包可能是JavaScript里最被人神乎其神的一个概念,世间万物皆凡夫俗子,你觉着他神奇是因为你根本没有了解,所有的事物当你了解透彻后就不会有这种不明觉厉的错觉了。哈哈哈,上来又是一顿哲学普及。

  下面开始进行阐述。

  1.什么是闭包?

  参阅了很多资料,最后比较靠谱的解释就是“闭包是一个函数”。

  闭包是一个函数,什么样的函数才能叫做闭包?可以从他的作用上理解闭包就是能够读取其他函数内部变量的函数。

  2.闭包是怎么形成的?

  首先再回顾下JavaScript的作用域这个概念。JavaScript是函数作用域而不是块状作用域,也就是说JavaScript的作用域是以函数来划分的,函数内部的变量为私有变量,而相对的全局变量是指在所有的函数外部定义的变量。全局变量自动归为全局对象global的属性,在web浏览器中这个global对象由window对象来承担这个全局变量的角色。

  一般的,在函数内部声明的加了var声明符的(函数内部定义变量不加var的话会默认声明为全局变量,为了避免全局空间变量污染所以要谨记)变量,在这个函数执行时候创建该函数相关的作用域,函数当然会有嵌套,所以就会存在作用域链接作用域的问题,也就是所说的作用域链。这个作用域链从最里层函数作用域开始,逐渐向外层链接,一层一层直到最外层的全局作用域。所以在内层的函数使用某个变量的时候会按照这个链接顺序去寻找,如果中途找到则停止,直到全局作用域还没有找到则该变量为未定义。

  正常情况,一个函数在调用开始执行时创建这个函数执行上下文及相应的作用域链,在函数执行结束后释放函数执行上下文及相应作用域链所占的空间。

  明白了作用域后再来看闭包怎样才能读取到其它函数的内部变量这个问题。首先,如果是函数A嵌套函数B,函数B自然可以访问函数A里的变量,向上还可以直到全局作用域的变量。这种情况肯定形成不了闭包。所以闭包是在某函数A之外的函数B想要访问函数A内部的变量下形成的。

  3.闭包怎么样才能读取到其它函数的内部变量

  最常见的形式就是在函数内部返回一个函数,这个返回的函数有引用外部函数的变量。示例代码如下:

function foo() {
var tmp = 0;
return function () {
console.log(tmp = tmp + 1);
}
}
var bar = foo(); // foo()执行后返回内部匿名函数,所以bar现在就是内部的那个函数的引用
bar(); //现在执行bar,也就是执行内部的那个匿名函数,输出为1,
bar(); //紧接着再执行bar,输出为2,也就是说foo函数内部的tmp变量不仅被外部的函数访问到了,而且tmp的值没有被清空,会累加

  这就满足了形成闭包的条件,即相对函数A(这里指foo())而言他外部的函数B(这里指bar(),其实bar只是内部匿名函数的引用在外部执行)访问到了A作用域的变量tmp,而且值的注意的是tmp变量一直存在于内存中。

  依据上边这段代码解释为什么变量会一直存在于内存中而不是随着函数执行完毕后就被垃圾回收。

  首先,bar是在外部作用域中,大部分时候是在全局作用域中,而全局作用域中的变量是一直存在于内存中的,所以当bar引用foo的时候,间接地foo也会一直存在于内存中,既然foo都一直存在于内存中,那foo所形成的函数作用域里的一切都会一直存在于内存中,因此就会出现上边看到的访问到的内部变量不会随着函数执行完后进行垃圾回收的情况。

  4.怎样才能理解闭包?

  首先明白他是一个能访问其它函数内部作用域变量的函数,打破了常规的函数作用域的限制,再理解就是他引用的变量会一直存在于内存中。

  下面贴一些闭包的代码,都是从其他地方看到的:

var object = {
a: 1,
getA: function () {
console.log(this.a=this.a+1);
}
}
object.getA();//输出为2
object.getA();//输出为3

  

var add = (function () {
var counter = 0;
return function () {return counter += 1;}
})();

  5.闭包都有什么用处? 

  1)一个是前面提到的可以读取函数内部的变量
  2)另一个就是让这些变量的值始终保持在内存中。
  6.使用闭包需要注意的地方有哪些?
  1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
  2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
 
  完!祝好运。

深入理解JavaScript系列:试着谈谈闭包的更多相关文章

  1. 深入理解JavaScript系列(16):闭包(Closures)

    介绍 本章我们将介绍在JavaScript里大家经常来讨论的话题 —— 闭包(closure).闭包其实大家都已经谈烂了.尽管如此,这里还是要试着从理论角度来讨论下闭包,看看ECMAScript中的闭 ...

  2. 深入理解javascript系列(4):立即调用的函数表达式

    本文来自汤姆大叔 前言 大家学JavaScript的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行. 在详细了解这个之前,我们来谈了解一下“自执行”这个叫法,本文对这个功能的叫法 ...

  3. 深入理解JavaScript系列

    转自http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html 深入理解JavaScript系列(1):编写高质量JavaScript代码 ...

  4. [JS]深入理解JavaScript系列(4):立即调用的函数表达式

    转自:汤姆大叔的博客 前言 大家学JavaScript的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行.在详细了解这个之前,我们来谈了解一下"自执行"这个叫法 ...

  5. 深入理解JavaScript系列(转自汤姆大叔)

    深入理解JavaScript系列文章,包括了原创,翻译,转载,整理等各类型文章,如果对你有用,请推荐支持一把,给大叔写作的动力. 深入理解JavaScript系列(1):编写高质量JavaScript ...

  6. [转]深入理解JavaScript系列

    文章转自:汤姆大叔-深入理解JavaScript系列文章 深入理解JavaScript系列文章,包括了原创,翻译,转载,整理等各类型文章,如果对你有用,请推荐支持一把,给大叔写作的动力. 深入理解Ja ...

  7. [转载]深入理解JavaScript系列 --汤姆大叔

    深入理解JavaScript系列文章,包括了原创,翻译,转载,整理等各类型文章,如果对你有用,请推荐支持一把,给大叔写作的动力. 深入理解JavaScript系列(1):编写高质量JavaScript ...

  8. 深入理解JavaScript系列(转载)

    深入理解JavaScript系列 深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点 深入理解JavaScript系列(2):揭秘命名函数表达式 深入理解JavaSc ...

  9. 深入理解JavaScript系列(49):Function模式(上篇)

    介绍 本篇主要是介绍Function方面使用的一些技巧(上篇),利用Function特性可以编写出很多非常有意思的代码,本篇主要包括:回调模式.配置对象.返回函数.分布程序.柯里化(Currying) ...

  10. 深入理解JavaScript系列(47):对象创建模式(上篇)

    介绍 本篇主要是介绍创建对象方面的模式,利用各种技巧可以极大地避免了错误或者可以编写出非常精简的代码. 模式1:命名空间(namespace) 命名空间可以减少全局命名所需的数量,避免命名冲突或过度. ...

随机推荐

  1. JavaScript中的splice方法

    splice方法根据传入的不同参数可分别实现删除和插入操作 使用splice(pra1,pra2,pra3)方法,需要为其提供如下参数: 1.pra1为其起始索引(即希望开始添加元素的地方) 2.pr ...

  2. 即时聊天IM之四 Android客户端IM帮助类编写

    图文无关一起娱乐: 这一篇我们开始写Android端的Smack版主类,后面Android的IM功能都是通过这个帮助类实现的 引用类库: 因为我用的是IDE是Android Studio,所以我通过g ...

  3. Zotero 使用指南

    DownLoad Page: https://onedrive.live.com/redir?resid=5084666E7B16AA85!109&authkey=!ABHQp7yfMnLpE ...

  4. react native 页面跳转

    React Native目前有几个内置的导航器组件,一般来说我们首推Navigator.它使用纯JavaScript实现了一个导航栈,因此可以跨平台工作 场景简单来说其实就是一个全屏的React组件. ...

  5. javascript数组的方法总结,非常实用的!

    在ES5中,一共有9个Array方法 http://kangax.github.io/compat-table/es5/ 注* 九个方法 Array.prototype.indexOfArray.pr ...

  6. DEVEXPRESS控件使用技巧记录-GRIDCONTROL

    1. 存在父子表的时候,只允许父表的一条记录展开,其他记录都收起 方法:Feature Browser -> Master-Detail -> behavior -> AllowOn ...

  7. 繁星——jquery的data()方法

    今天在看JQuery文档的时候偶然看到了data()方法,觉得挺好用的,这里做个记录. 这个方法用于在元素上存放数据,返回jQuery对象.在文档中提到V1.4.3 新增用法NEW data(obj) ...

  8. 高性能javascript(记录三)

    DOM(文档对象模型)是一个独立的语言,用于操作XML和HTML文档的程序接口(API).在游览器中,主要用来与HTML文档打交道,同样也用在Web程序中获取XML文档,并使用DOM API用来访问文 ...

  9. 一个Woker类,当id和name相同时,系统判断两个工人是相等的,打印工人对象时显示“工人:id和name”。

    public class Worker { private int id; private String name; private double salary; public boolean equ ...

  10. Memcached(1)-----基本介绍

    memcached memcached概述 memcached是LiveJournal旗下Danga Interactive公司开发的一款软件.memcached是一个高性能,分布式内存对象缓存系统, ...