闭包(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. Bootstrap_Javascript_固定定位

    Affix 插件可以对任何元素进行固定定位,其中比较简单的方法,就是通过自定义属性 data 来触发.其主要包括两个参数: 1.data-spy:取值 affix,表示元素固定不变的. 2.data- ...

  2. 织梦dedecms后台发布文章不自动更新首页与栏目列表页

    dedecms发文章不自动更新首页也列表页解决办法如下: 登陆dedecms后台,找到“系统”“系统基本参数”“性能选项”,把“arclist标签调用缓存”设置成0,然后把“发布文章后马上更新网站主页 ...

  3. yii框架的foreach 已经优化好了,可以“$user_model->attributes=$_POST['Admin'];”

    yii框架的foreach 已经优化好了, 以前我们遍历数组的时候是用foreach循环 foreach ( as $key=>$value){                    $user ...

  4. strcpy实现

    #include <iostream> using namespace std; char *strcpy(char *strDest, const char *strSrc) { if ...

  5. jQuery折叠风琴

    这个效果用jQuery做是很方便的,根本不需要搞得很复杂. 网上有些效果DEMO不仅用了jQuery还引用一两个封装文件,真是匪夷所思. 最初想到了toggle: jQuery(document).r ...

  6. Flip Game

    http://poj.org/problem?id=1753 #include<cstdio> #include<algorithm> #include<string.h ...

  7. H3C S5000和H3C S5500,俺来罗

    S5开头,后面第二位数0-4搂二层交换机.5-9的为三层交换机. 小常识.

  8. C51 I2C接口驱动,IO口模拟I2C(主+从)

    Master.asm ;/*------------------------------------------------------------------*/ ;/* --- STC MCU I ...

  9. 7.DropDownList的绑定

    ListView中是无法像TextBox等控件那样将DropDownList的选中值绑定到数据字段的,必须编程处理.如例子:人员的性别(男,女,保密),三个值固定写在DropDownList中. 在显 ...

  10. 【Linux】鸟哥的Linux私房菜基础学习篇整理(七)

    1. test命令的测试功能.测试的标志:(1)关于文件类型的检测 test [-efdbcSpL] filename-e:该文件名是否存在:-f:该文件名是否为文件:-d:该文件名是否为目录:-b: ...