闭包可能是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. java 的 sqlHelper,改改之后也适用于不使用 EF 的 C# 项目,包含查询和建表。

    这个类用来拼接 sql. package com.ly.orm; public class Query { protected Query(String v) { sql = v; } public ...

  2. linq 日期分组统计

     #region        string Condition(DateTime date, string type)        {            if (date == null)   ...

  3. kendo模板 Uncaught Error: Invalid template:' 报错

    I was having a problem with a grid toolbar template because of a # in a hrefWorked out that I needed ...

  4. java解析XML文件

    dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的.dom4j是一个非常非常优秀的Java XML API,具有性能优异.功能强大和极端易用使用的特点,同时它也是一个开放源 ...

  5. AsyncTask

    package com.gg.test; import java.io.IOException; import org.apache.http.HttpResponse;import org.apac ...

  6. win8.1安装Matlab7.0的兼容问题

     Matlab7.0安装完成后打开就立即关闭,此时右键点击MATLAB7.0快捷方式-"用图形处理器运行"-"更改默认图形处理器",将"集成图形&qu ...

  7. iOS UISearchBar 设置取消按钮,回收键盘,并修改cancel为“取消”

    继承协议: UISearchBarDelegate 在代理方法中设置: #pragma mark --- 搜索框开始编辑 --- - (void)searchBarTextDidBeginEditin ...

  8. CVPR历年Best Papers

    作者:我爱机器学习原文链接:CVPR历年Best Papers CVPR (Computer Vision)(2000-2016) 年份 标题 一作 一作单位 2016 Deep Residual L ...

  9. Raspberry Pi Resources-Using the UART

    参考:RPi Serial Connection 本文来自:http://www.raspberry-projects.com/pi/programming-in-c/uart-serial-port ...

  10. mac brew mysql 启动之后报错

    打开电脑 链接mysql 发现报错,连不上,应该是没自启动, 之前一直用windows电脑,就用mysql start 准备启动下,发现报错, p.p1 { margin: 0.0px 0.0px 0 ...