JavaScript闭包(Closure)

本文收集了多本书里对JavaScript闭包(Closure)的解释,或许会对理解闭包有一定帮助。

《你不知道的JavsScript》

  1. JavaScript 中闭包无处不在,你只需要能够识别并拥抱它。
  2. 闭包是基于词法作用域书写代码时所产生的自然结果。
  3. 当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。
  4. 无论通过何种手段将内部函数传递到所在的词法作用域以外,它都会持有对原始定义作用域的引用,无论在何处执行这个函数都会使用闭包。
  5. 无论何时何地,如果将函数(访问它们各自的词法作用域)当作第一级的值类型并到处传递,你就会看到闭包在这些函数中的应用。在定时器、事件监听器、 Ajax 请求、跨窗口通信、Web Workers 或者任何其它的异步(或者同步)任务中,只要使用了回调函数,实际上就是在使用闭包。

《JavaScript编程解析》

1. 对闭包的初步认识

var fn = f();     // 将函数f 的返回值赋值给变量fn
fn(); // 1
fn(); //2
fn(); //3 function f() {
var cnt = 0;
return function() { return ++cnt; }
} var fn1 = f1();
fn1(); //1
fn1(); //1 function f1(){
var cnt = 0;
return ++cnt;
}

从表面上来看,闭包是一种具有状态的函数。或者也可以将闭包的特征理解为,其相关的局部变量在函数调用结束之后将会继续存在。

2. 闭包的原理

  1. 闭包的前提条件是需要在函数声明的内部声明另一个函数(即嵌套的函数声明)。
  2. 闭包指的是一种特殊的函数,这种函数会在被调用时保持当时的变量名查找的执行环境。
  3. 闭包仅仅是保持了变量名查找的状态,而并没有保持对象所有的状态,对此请加以区分。也就是说,闭包虽然会保持(在嵌套外层进行函数调用时被隐式地生成的)Call 对象,但无法保持 Call 对象的属性所引用的之前的对象的状态。

3. 防范命名空间的污染

  1. 模块

  2. 避免使用全局变量

  3. 通过实现信息隐藏

     //使用了闭包的模块
    // 在此调用匿名函数
    // 由于匿名函数的返回值是一个函数,所以变量sum 是一个函数
    var sum = (function() {
    // 无法从函数外部访问该名称
    // 实际上,这变成了一个私有变量
    // 一般来说,在函数被调用之后该名称就将无法再被访问
    // 不过由于是在被返回的匿名函数中,所以仍可以继续被使用
    var position = { x:2, y:3 }; // 同样是一个从函数外部无法被访问的私有变量
    // 将其命名为sum 也可以。不过为了避免混淆,这里采用其他名称
    function sum_internal(a, b) {
    return Number(a) + Number(b);
    } // 只不过是为了使用上面的两个名称而随意设计的返回值
    return function(a, b) {
    print('x = ', position.x);
    return sum_internal(a, b); };
    }
    )(); // 调用
    sum(3, 4);
    x = 2
    7

在利用函数作用域可以封装名称,以及闭包可以使名称在函数调用结束后依然存在这两个特性后,信息隐藏得以实现。

(function() { 函数体 })();

4.闭包与类

  1. 计数器功能的类

     function counter_class(init) {                  // 初始值可以通过参数设定
    var cnt = init || 0; // 设置默认参数的习惯做法(参见5.5 节) // 如有必要,可在此声明私有变量与私有函数 return {
    // 公有方法
    show:function() { print(cnt); },
    up:function() { cnt++; return this; }, // return this 在使用方法链时很方便
    down:function() { cnt--; return this; }
    };
    } // 使用代码
    var counter1 = counter_class();
    counter1.show();
    0
    counter1.up();
    counter1.show();
    1 var counter2 = counter_class(10);
    counter2.up().up().up().show(); // 方法链
    13
  2. 表达式闭包

JavaScript 有一种自带的增强功能,称为支持函数型程序设计的表达式闭包(Expression closure)。

	var sum = function(a, b) { return Number(a) + Number(b); }
//可以省略为
var sum = function(a, b) Number(a) + Number(b);

5.闭包与回调函数

《JavaScript高级程序设计》

  1. 闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数
  2. 当某个函数被调用时,会创建一个执行环境(execution context)及相应的作用域链。
  3. 由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度使用闭包可能会导致内存占用过多,我们建议读者只在绝对必要时再考虑使用闭包。

内存泄漏

由于IE9之前的版本对JScript对象和COM对象使用不同的垃圾收集例程,因此闭包在IE的这些版本中会导致一些特殊的问题。具体来说,如果闭包的作用域链中保存着一个HTML元素,那么就意味着该元素将无法被销毁。

function assignHandler(){
var element = document.getElementById("someElement");
element.onclick = function(){
alert(element.id);
};
} //把element变量设置为null。这样就能够解除对DOM对象的引用,顺利地减少其引用数,确保正常回收其占用的内存。 function assignHandler(){
var element = document.getElementById("someElement");
var id = element.id; element.onclick = function(){
alert(id);
}; element = null;
}

《JavaScript设计模式与开发实践》

1. 闭包更多作用

  1. 封闭变量

  2. 延续局部变量的寿命

     //把img变量用闭包封闭起来,便能解决请求丢失的问题
    var report = (function(){
    var imgs = [];
    return function( src ){
    var img = new Image();
    imgs.push( img );
    img.src = src;
    }
    })();

2. 闭包与内存管理

  1. 局部变量本来应该在函数退出的时候被解除引用,但如果局部变量被封闭在闭包形成的环境中,那么这个局部变量就能一直生存下去。如果在将来需要回收这些变量,我们可以手动把这些变量设为null。
  2. 跟闭包和内存泄露有关系的地方是,使用闭包的同时比较容易形成循环引用,如果闭包的作用域链中保存着一些DOM节点,这时候就有可能造成内存泄露。但这本身并非闭包的问题,也并非JavaScript的问题。
  3. 如果要解决循环引用带来的内存泄露问题,我们只需要把循环引用中的变量设为null即可。将变量设置为null意味着切断变量与它此前引用的值之间的连接。当垃圾收集器下次运行时,就会删除这些值并回收它们占用的内存。

《JavaScript权威指南》

  1. JavaScript也采用词法作用域(lexical scoping),也就是说,函数的执行依赖于变量作用域,这个作用域是在函数定义时决定的,而不是函数调用时决定的。为了实现这种词法作用域,JavaScript函数对象的内部状态不仅包含函数的代码逻辑,还必须引用当前的作用域链。函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性在计算机科学文献中称为“闭包”。
  2. 从技术的角度讲,所有的JavaScript函数都是闭包:它们都是对象,它们都关联到作用域链。
  3. 是如果这个函数定义了嵌套的函数,并将它作为返回值返回或者存储在某处的属性里,这时就会有一个外部引用指向这个嵌套的函数。它就不会被当做垃圾回收,并且它所指向的变量绑定对象也不会被当做垃圾回收。

转载请注明出处:http://www.cnblogs.com/givebest/p/5617565.html

JavaScript闭包(Closure)的更多相关文章

  1. 深入理解JavaScript闭包(closure)

    最近在网上查阅了不少javascript闭包(closure)相关的资料,写的大多是非常的学术和专业.对于初学者来说别说理解闭包了,就连文字叙述都很难看懂.撰写此文的目的就是用最通俗的文字揭开Java ...

  2. [转载]学习Javascript闭包(Closure)

    学习Javascript闭包(Closure)     源地址: http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures ...

  3. javascript 闭包(closure)

    <script type="text/javascript">    //闭包(closure):内层函数可以引用存在于包围它的函数内的变量,即使外层函数的执行已经结束 ...

  4. JavaScript闭包(closure)入门: 拿"开发部"和"技术牛"举个例子

    虽然只是一小段菜鸟的学习笔记 , 不过还是希望看到的高手看到不足的时候帮忙指点~ 一:代码和执行过程 /** * http://blog.csdn.net/ruantao1989 * ==>Ju ...

  5. JavaScript闭包(二)——作用

    一.延迟调用 当在一段代码中使用 setTimeout 时,要将一个函数的引用作为它的第一个参数,而将以毫秒表示的时间值作为第二个参数. 但是,传递函数引用的同时无法为计划执行的函数提供参数.可以在代 ...

  6. JavaScript闭包(一)——实现

    闭包的官方的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. 通俗点的说法是: 从理论角度:所有的函数.因为它们都在创建的时候就将上层上下文 ...

  7. JavaScript闭包——实现

    闭包的官方的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. 通俗点的说法是: 从理论角度:所有的函数.因为它们都在创建的时候就将上层上下文 ...

  8. JavaScript学习总结(十六)——Javascript闭包(Closure)

    原文地址: http://www.cnblogs.com/xdp-gacl/p/3703876.html 闭包(closure)是Javascript语言的一个难点,也是它的特色, 很多高级应用都要依 ...

  9. javascript中的闭包closure详解

    目录 简介 函数中的函数 Closure闭包 使用闭包实现private方法 闭包的Scope Chain 闭包常见的问题 闭包性能的问题 总结 简介 闭包closure是javascript中一个非 ...

随机推荐

  1. linux-图形化远程管理协议

    远程管理控制方式: RDP(remote desktop protocol)协议: telnet: SSH(Secure Shell): RFB(Remote FrameBuffer)协议(图形化远程 ...

  2. oracle 存储过程

    来自:http://www.jb51.net/article/31805.htm Oracle存储过程基本语法 存储过程 1 CREATE OR REPLACE PROCEDURE 存储过程名 2 I ...

  3. 性能测试工具 wrk 安装与使用

    介绍 今天给大家介绍一款开源的性能测试工具 wrk,简单易用,没有Load Runner那么复杂,他和 apache benchmark(ab)同属于性能测试工具,但是比 ab 功能更加强大,并且可以 ...

  4. MyBatis5:MyBatis集成Spring事物管理(上篇)

    前言 有些日子没写博客了,主要原因一个是工作,另一个就是健身,因为我们不仅需要努力工作,也需要有健康的身体嘛. 那有看LZ博客的网友朋友们放心,LZ博客还是会继续保持更新,只是最近两三个月LZ写博客相 ...

  5. Lesson 17 Always young

    Text My aunt Jennifer is an actress. She must be at least thirty-five years old. In spit of this, sh ...

  6. 关于VS2015支持编译Linux程序的问题

    现状 目前已经发布的VS2015中包括VS2015 Preview 以及 VS2015 CTP6,这两个版本均不支持直接编译C++代码为Linux程序,具体情况可以参考 Visual Studio 2 ...

  7. WCF中,通过C#代码或App.config配置文件创建ServiceHost类

    C# static void Main(string[] args) { //创建宿主的基地址 Uri baseAddress = new Uri("http://localhost:808 ...

  8. Linex 配置php服务器

    此文是可以参考 楼主也不是系统管理员只是迫不得已所以自己才找的  大家可以参考 .... ..... 安装apache 安装mysql 安装PHP 测试服务器 php -v 查询php的版本 就这些了 ...

  9. HTML5之应用缓存---manifest---缓存使用----Web前端manifest缓存

    相信来查这一类问题的都是遇到问题或者是初学者吧! 没关系相信你认真看过之后就会知道明白的 这是HTML5新加的特性 HTML5 引入了应用程序缓存,这意味着 web 应用可进行缓存,并可在没有因特网连 ...

  10. 初学者--bootstrap(六)组件中的下拉菜单----在路上(10)

    组件---下拉菜单 用于显示链接列表的可切换.有上下文的菜单.下拉菜单的 JavaScript 插件让它具有了交互性. 将下拉菜单触发器和下拉菜单都包裹在 .dropdown 里,或者另一个声明了 p ...