昨天晚上听别人谈起闭包这个东西,虽然对js有一点了解但却丝毫没有印象,今天也没什么事就顺便研究了一下满足好奇宝宝。整合于网上的理解,记录一下。

一、闭包的作用域

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

  • 全局作用域
  • 局部作用域 :一个 function 形成一个独立的作用域, 而且方法作用域还能够嵌套.

  与别的语言不同的是: 花括号({})不能形成一个独立的作用域, 例如Java中的作用域. 

 下面我们举例说说作用域

 var m = 1;
 function f(){
     //这里面就形成了一个方法作用域, 能够保护其中的变量不能被外部访问
      //方法作用域能够访问全局作用域
      var n = 2;
      alert(m);//会弹出m值
     // 嵌套方法作用域
     function f1(){
         // 这里面再度形成了一个方法作用域
         // 其中可以访问外部的那个方法作用域
         var n1 = 3;
         alert(n);
      }
      //出了f1作用域就不能访问f1的变量了
      //alert(n1); 报错
 }

二、闭包

弄清楚作用域的问题后, 我们就可以开始聊聊闭包了。

我们以最经典的for循环为例来讲解. 大家可以试试下面这段代码, 取自JavaScript 秘密花园循环中的闭包

for(var i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i);
    }, 1000);
}

输出结果为 10个10 ;

如果在运行前, 你没有猜到正确答案, 那就对了...

  • 首先说说为什么最终输出的是10次10, 而不是你想象中的 0, 1, 2, 3, 4, 5, 6, 7, 8,9

因为setTimeout是异步的!

你可以想象由于setTimeout是异步的, 因此我们将这个for循环拆成2个部分

第一个部分专门处理 i 值的变化, 第二个部分专门来做setTimeout

因此我们可以得到如下代码:

  • // 第一个部分
       i++;
       ...
       i++; // 总共做10次
    
       // 第二个部分
       setTimeout(function() {
          console.log(i);
       }, 1000);
       ...
       setTimeout(function() {
          console.log(i);
       }, 1000); // 总共做10次

    这样一拆后, 我相信你肯定知道之前那个for循环的运行结果了.

由于循环中的变量 i 一直在变, 最终会变成10, 而循环每每执行setTimeout时, 其中的方法还没有真正运行, 等真正到时间执行时, i 的值已经变成 10 了! 

    i 变化的整个过程是瞬间完成的, 总之比你异步要快, 就算你setTimout是0毫秒也一样, 会先于你执行完成.

  • for(var i = 0; i < 10; i++) {
           setTimeout(function() {
               console.log(i);
           }, 0);
       }
  • 那么为什么setTimeout中匿名function没有形成闭包呢?

   因为setTimeout中的匿名function没有将 i 作为参数传入来固定这个变量的值, 让其保留下来, 而是直接引用了外部作用域中的 i, 因此 i 变化时, 也影响到了匿名function.

   因此如果我们定义一个外部函数, 让 i 作为参数传入即可"闭包"我们要的变量了!!

   for (var i = 0; i < 10; i++) {
       // 注意关键是我们把想要闭包的值当参数传入一个方法
       // 这个方法 return 一个新的方法 -- 闭包!!
       setTimeout(fn(i), 1000);
   }
   function fn() { // 为了深刻理解闭包, 这个函数我没有用参数
       // 神奇的"闭包"发生在这一步, 其实就是作用域和值复制在起了关键作用,
       // 对于数字/字符等类型是复制值, 而不是引用
       var a = arguments[0];
       return function() {
           console.log(a); // 注意现在我操作的变量已经变成 a 了,
                                     // 已经和 i 没有半毛线关系了!
                                     // 而 a 的值就是当时执行时赋予的一个确定值,
                                     // 不会因 i 的变化而变化了!
       };
   }
  • 再换成更简洁的方式看你能不能真正理解闭包
   for (var i = 0; i < 10; i++) {
       (function(a) {
           // 变量 i 的值在传递到这个作用域时被复制给了 a,
           // 因此这个值就不会随外部变量而变化了
           setTimeout(function() {
               console.log(a);
           }, 1000);
       })(i); // 我们在这里传入参数来"闭包"变量
   }

这就是闭包, 简单点说就是专门用来"包养"变量的.

总结:

(1)闭包是一种设计原则,它通过分析上下文,来简化用户的调用,让用户在不知晓的情况下,达到他的目的;

(2)网上主流的对闭包剖析的文章实际上是和闭包原则反向而驰的,如果需要知道闭包细节才能用好的话,这个闭包是设计失败的;

(3)尽量少学习。

JavaScript ——闭包理解的更多相关文章

  1. javascript闭包理解

    //闭包理解一 function superFun(){ var _super_a='a'; function subfuc(){ console.log(_super_a); } return su ...

  2. 对于 Javascript 闭包理解

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

  3. javascript 闭包理解

    摘自:http://www.cnblogs.com/jkswjw/p/3180384.html javascript 闭包基础分享 闭包向来给包括JavaScript程序员在内的程序员以神秘,高深的感 ...

  4. JavaScript闭包理解【关键字:普通函数、闭包、解决获取元素标签索引】

    以前总觉得闭包很抽象,很难理解,所以百度一下"闭包"概览,百度的解释是:“闭包是指可以包含自由(未绑定到特定对象)变量的代码块:这些变量不是在这个代码块内或者任何全局上下文中定义的 ...

  5. JavaScript闭包理解的关键 - 作用域链

    阮一峰的一篇文章已经对闭包的用途.概念讲解地相对清晰了. 闭包就是能够读取其他函数内部变量的函数. 但我认为里面对于作用域链的解释还不够清晰,这里作一些补充. 闭包之所以可以读取外部函数的内部变量,即 ...

  6. 关于javascript闭包理解

    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一:关于变量的作用域 Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. ...

  7. JavaScript闭包理解【关键字:普通函数、变量访问作用域、闭包、解决获取元素标签索引】

        一.闭包(Closure)模糊概述 之前总觉得闭包(Closure)很抽象而且难理解,百度一下"闭包"名词,百度的解释是:“闭包是指可以包含自由(未绑定到特定对象)变量的代 ...

  8. javascript 闭包理解例子

    function Jquery(){ this.name = 'ysr'; this.sex = 'man'; return { x: this, age : 26 } } var b = new J ...

  9. javascript深入理解js闭包

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

随机推荐

  1. shell与kernel的理解 转载

    Shell 的英文释义是外壳,与 kernel 内核名词遥相呼应,一外一内,一壳一核.内核就像瑞士银行的金库,存放着客户的黄金等众多的(硬件)资产,闲杂人等(包括客户)当然是严格禁止入内的,而作为客户 ...

  2. 设置MySQL开机自动启动的方法

    在windows中一般情况下mysql安装好之后就是开机自动启动不需要设置,但是如果是通过yum安装MySQL后,默认开机时不会自动启动,需要手动设置MySQL让它开机自启动. 首先,通过chkcon ...

  3. HTML(Open Method)翻译自MSDN

    Open Method Opens a new window and loads the document specified by a given URL. Navigates the app wi ...

  4. TCP/IP协议简介

    计算机网络是什么? 简单地理解,计算机网络的任务就是传输数据.为了完成这一复杂的任务,国际标准化组织ISO提供了OSI参考模型,这种模型把互联网网络氛围7层,分别是物理层.数据链路层.网络层.传输层. ...

  5. jquery之html(),text()方法详解

    一:html() html()函数用于设置或返回当前jQuery对象所匹配的DOM元素内的html内容. 该函数的用途相当于设置或获取DOM元素的innerHTML属性值. 该函数属于jQuery对象 ...

  6. QUEEN_BLADE_2D-非常屌-113P

    http://www.cgvoo.com/thread-33670-1-2.html http://blog.sina.com.cn/s/blog_4b92d6070102e7gj.html http ...

  7. Installing Python 3.5.2 from source

    Here are the procedures we are to follow, Download the source code of an official Python release. Co ...

  8. phpcms 在后台增加了一个模型的话,在数据库中就会相应的增加数据库表

    在phpcms后台管理系统中,我们如果增加一个新的模型的话,例如名为:测试模型,英文名:test 在添加完成后,我们在数据库中发现增加了两个数据表:v9_test,v9_test_data;

  9. E2 2014.5.8 更新日志

    增加功能 增加报价单功能,可以针对指定客户生成报价单,可以直接生成一个在线地址,直接把地址发给客户在线打开 传统的报价,先生成一个EXCEL,再传给客户,使用E2,这一切都变得简单,你可生成一个在线地 ...

  10. iOS - Swift Closure 闭包

    1.Closure 闭包在 Swift 中非常有用.通俗的解释就是一个 Int 类型里存储着一个整数,一个 String 类型包含着一串字符,同样,闭包是一个包含着函数的类型.有了闭包,你就可以处理很 ...