闭包(closure)是Javascript语言的一个难点。也是它的特色,非常多高级应用都要依靠闭包实现。

一、什么是闭包?

官方”的解释是:闭包是一个拥有很多变量和绑定了这些变量的环境的表达式(一般是一个函数),因而这些变量也是该表达式的一部分。

相信非常少有人能直接看懂这句话,由于他描写叙述的太学术。事实上这句话通俗的来说就是:JavaScript中全部的function都是一个闭包。只是一般来说,嵌套的function所产生的闭包更为强大。也是大部分时候我们所谓的“闭包”。

要理解闭包,首先必须理解Javascript特殊的变量作用域。

二、变量的作用域

变量的作用域无非就是两种:全局变量和局部变量。

Javascript语言的特殊之处。就在于函数内部能够直接读取全局变量。

var n=999;

function f1(){
alert(n);
} f1(); // 999

还有一方面,在函数外部自然无法读取函数内的局部变量。

function f1(){
  var n=999;
} alert(n); // error

这里有一个地方须要注意,函数内部声明变量的时候。一定要使用var命令。假设不用的话,你实际上声明了一个全局变量!

function f1(){
   n=999;
} f1(); alert(n); // 999

三、怎样从外部读取局部变量?

出于种种原因,我们有时候须要得到函数内的局部变量。可是,前面已经说过了,正常情况下,这是办不到的,仅仅有通过变通方法才干实现。

那就是在函数的内部,再定义一个函数。

function f1(){
n=999;
function f2(){
      alert(n); // 999
    }
}

在上面的代码中,函数f2就被包含在函数f1内部,这时f1内部的全部局部变量。对f2都是可见的。可是反过来就不行。f2内部的局部变量,对f1 就是不可见的。

这就是Javascript语言特有的“链式作用域”结构(chain scope),

子对象会一级一级地向上寻找全部父对象的变量。所以,父对象的全部变量。对子对象都是可见的,反之则不成立。

既然f2能够读取f1中的局部变量,那么仅仅要把f2作为返回值。我们不就能够在f1外部读取它的内部变量了吗。

function f1(){

    n=999;

    function f2(){
      alert(n);
    }     return f2; } var result=f1(); result(); // 999

上面代码中的f2函数,就是闭包。

各种专业文献上的“闭包”(closure)定义非常抽象,非常难看懂。我的理解是。闭包就是可以读取其它函数内部变量的函数。

因为在Javascript语言中。仅仅有函数内部的子函数才干读取局部变量,因此能够把闭包简单理解成“定义在一个函数内部的函数”。

所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

四、闭包的用途

闭包能够用在很多地方。它的最大用处有两个,一个是前面提到的能够读取函数内部的变量。还有一个就是让这些变量的值始终保持在内存中。

怎么来理解这句话呢?请看以下的代码。

function f1(){

    var n=999;

    nAdd=function(){n+=1}

    function f2(){
      alert(n);
    }     return f2; }
var result=f1();
result(); // 999
nAdd();
result(); // 1000

在这段代码中,result实际上就是闭包f2函数。它一共执行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中。并没有在f1调用后被自己主动清除。

为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中。而f2的存在依赖于f1,因此f1也始终在内存中。不会在调用结束后,被垃圾回收机制(garbage collection)回收。

这段代码中还有一个值得注意的地方,就是“nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用varkeyword。因此 nAdd是一个全局变量,而不是局部变量。

其次。nAdd的值是一个匿名函数(anonymous function)。而这个

匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,能够在函数外部对函数内部的局部变量进行操作。

五、使用闭包的注意点

1)因为闭包会使得函数中的变量都被保存在内存中。内存消耗非常大,所以不能滥用闭包。否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量所有删除。

2)闭包会在父函数外部。改变父函数内部变量的值。

所以,假设你把父函数当作对象(object)使用。把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便

改变父函数内部变量的值。

六、思考题

假设你能理解以下代码的执行结果。应该就算理解闭包的执行机制了。

var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      return function(){
        return this.name;
     };
    }
};
alert(object.getNameFunc()()); //The Window

七、JavaScript闭包样例

function outerFun()
{
var a=0;
function innerFun()
{
a++;
alert(a);
}
}
innerFun() //上面的代码是错误的.innerFun()的作用域在outerFun()内//部,所在outerFun()外部调用它是错误的. //改成例如以下,也就是闭包: function outerFun()
{
var a=0;
function innerFun()
{
a++;
alert(a);
}
return innerFun; //注意这里
}
var obj=outerFun();
obj(); //结果为1
obj(); //结果为2
var obj2=outerFun();
obj2(); //结果为1
obj2(); //结果为2

再次来看什么是闭包?

当内部函数 在定义它的作用域 的外部 被引用时,就创建了该内部函数的闭包 ,假设内部函数引用了位于外部函数的变量,当外部函数调用完成后,这些变量在内存不会被 释放,由于闭包须要它们。

再来看一个样例

function outerFun()
{
var a =0;
alert(a);
}
var a=4;
outerFun();
alert(a);

结果是 0 , 4 .  由于在函数内部使用了varkeyword 维护a的作用域在outFun()内部.

再看以下的代码:

unction outerFun()
{
//没有var
a =0;
alert(a);
}
var a=4;
outerFun();
alert(a);

结果为 0 , 0 真是奇怪,为什么呢?

作用域链是描写叙述一种路径的术语,沿着该路径能够确定变量的值 .当运行a=0时,由于没有使用varkeyword,因此赋值操作会沿着作用域链到var a=4;  并改变其值.

假设你对javascript闭包还不是非常理解,能够再看下篇文章

深入理解javascript闭包(一)的更多相关文章

  1. 我从来不理解JavaScript闭包,直到有人这样向我解释它...

    摘要: 理解JS闭包. 原文:我从来不理解JavaScript闭包,直到有人这样向我解释它... 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 正如标题所述,JavaScript闭包 ...

  2. 深入理解JavaScript闭包【译】

    在<高级程序设计>中,对于闭包一直没有很好的解释,在stackoverflow上翻出了一篇很老的<JavaScript closure for dummies>(2016)~ ...

  3. 【转】深入理解JavaScript闭包闭包(closure) (closure)

    一.什么是闭包?"官方"的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分.相信很少有人能直接看懂这句话,因为他描述 ...

  4. 全面理解Javascript闭包和闭包的几种写法及用途

    好久没有写博客了,过了一个十一长假都变懒了,今天总算是恢复状态了.好了,进入正题,今天来说一说javascript里面的闭包吧!本篇博客主要讲一些实用的东西,主要将闭包的写法.用法和用途.  一.什么 ...

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

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

  6. 深入理解javascript闭包(一)

    原文转自脚本之家(http://www.jb51.net/article/24101.htm) 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. ...

  7. 深入理解Javascript闭包概念

    一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部能够直接读取全局变量 ...

  8. 轻松理解JavaScript闭包

    摘要 闭包机制是JavaScript的重点和难点,本文希望能帮助大家轻松的学习闭包 一.什么是闭包? 闭包就是可以访问另一个函数作用域中变量的函数. 下面列举出常见的闭包实现方式,以例子讲解闭包概念 ...

  9. 【译】理解JavaScript闭包——新手指南

    闭包是JavaScript中一个基本的概念,每个JavaScript开发者都应该知道和理解的.然而,很多新手JavaScript开发者对这个概念还是很困惑的. 正确理解闭包可以帮助你写出更好.更高效. ...

随机推荐

  1. Fedora 18 安装前指南

    Secure Boot 与 Win 8   随着 Win8 的发布,先前关于 Secure Boot 和 UEFI 的诸多猜测也得到了证实,Fedora 18 也将如同当初计划的那样使用 shim + ...

  2. Mysql访问 for橙子小海

    package com.mvc.model.dao; import com.mvc.model.daoutil.DBConn; import com.mvc.model.entity.Blog; 这是 ...

  3. 阻止文件不被上传到iCloud-b

    有空用下 http://www.cocoachina.com/bbs/read.php?tid=86244 http://www.ooso.net/archives/617 http://blog.c ...

  4. hadoop 2.2.0 集群部署 坑

    注意fs.defaultFS为2..0新的变量,代替旧的:fs.default.name hadoop 2.2.0 集群启动命令:bin/hdfs namenode -formatsbin/start ...

  5. [BZOJ 1875] [SDOI 2009] HH去散步【矩阵乘法】

    题目链接:BZOJ - 1875 题目分析: 这道题如果去掉“不会立刻沿着刚刚走来的路走回”的限制,直接用邻接矩阵跑矩阵乘法就可以了.然而现在加了这个限制,建图的方式就要做一些改变.如果我们把每一条边 ...

  6. ConnectifyHotspotInstaller3.7注册码

    ConnectifyHotspotInstaller3.7注册码 邮箱: wcxu21@126.com 密 钥:QEX4HR-9VLS2N-AXFA3A-K8CD8M-1DQ7Q1-CCDDTB-KL ...

  7. 模拟I2C从机程序

    ;Slave.asm SCL BIT P1. SDA BIT P1. ;---------------------------- ORG RESET: SETB SCL SETB SDA CALL I ...

  8. 转:我终于离开了年薪30w的IT行业

    题目乍看起来有点故意惹人眼球的味道,但是对于我事实就是如此,暂且请君听我细细道来!      先自曝家门,我03年毕业,05年来深,06年买车子,06年底结婚,07年买了房子,09年生了儿子,妻子.房 ...

  9. [置顶] export命令-linux

    export 命令 功能说明: 设置或显示环境变量. 语 法: export [-fnp][变量名称]=[变量设置值] 补充说明: 在shell中执行程序时,shell会提供一组环境变量. expor ...

  10. Linux&shell之Shell脚本

    写在前面:案例.常用.归类.解释说明.(By Jim) 使用多条命令shell脚本的关键是可以输入多条命令,甚至可以将一条命令的结果传递给另一条命令.date;who(两个命令shell脚本的写法) ...