JavaScript ——闭包理解

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

一、闭包的作用域

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

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

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

 下面我们举例说说作用域

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

二、闭包

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

我们以最经典的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)尽量少学习。

时间: 2024-10-07 06:33:07

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

关于javascript闭包理解

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一:关于变量的作用域 Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. var n=999; function f1(){ alert(n); } f1(); // 999 另一方面,在函数外部自然无法读取函数内的局部变量. function f1(){ var n=999; } alert(n); // error 声明变量的时候记得使用var声明,不然的话java

javascript 闭包理解例子

function Jquery(){ this.name = 'ysr'; this.sex = 'man'; return { x: this, age : 26 } } var b = new Jquery(); //b => {x:Jquery, age:26} //b.x = Jquery; //b.x.name = 'ysr'; //b.x.sex = 'man' var b = Jquery();//b.x = window; 若果里面没return 的话: function Jqu

JavaScript闭包理解

闭包:一个函数引用(访问)另一个函数的变量 1 function a(){ 2 var n=0; 3 this.b = function(){ 4 n++; 5 console.log(n); 6 }; 7 } 8 9 var t=new a(); 10 t.b(); //输出1 11 t.b(); //输出2 函数b 访问了函数a中的变量n,所以形成了一个闭包.

深入理解javascript闭包

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. Js代码 var n=999; function f1(){ alert(n); } f1(); // 999 另一方面,在函数外部自然无法读取函数内的局部变量. Js代码 function

javascript深入理解js闭包

一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. Js代码 var n=999; function f1(){ alert(n); } f1(); // 999 另一方面,在函数外部自然无法读取函数内的局部变量. Js代码 function f1(){ var n=999; } alert(n); // error 这里有一个地方需要注意,函数

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

一.什么是闭包和闭包的几种写法和用法                                                       1.什么是闭包 闭包,官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分.闭包的特点: 1. 作为一个函数变量的一个引用,当函数返回时,其处于激活状态. 2. 一个闭包就是当一个函数返回时,一个没有释放资源的栈区. 简单的说,Javascript允许使用内部函数---即函数定义和函数表

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

转自:http://www.cnblogs.com/yunfeifei/p/4019504.html 好久没有写博客了,过了一个十一长假都变懒了,今天总算是恢复状态了.好了,进入正题,今天来说一说javascript里面的闭包吧!本篇博客主要讲一些实用的东西,主要将闭包的写法.用法和用途. 一.什么是闭包和闭包的几种写法和用法                                                       1.什么是闭包 闭包,官方对闭包的解释是:一个拥有许多变量和绑

javascript闭包的理解-韩烨

javascript闭包是javascript的难点,很多人对js闭包不是很理解,我对js闭包一开始也是云里雾里,我刚刚进兴安得力的时候,做的转正试题中就有一个对闭包理解的题目.如何理解javascript的闭包呢?下面我们一起来学习一下: 闭包的含义和理解 通俗地讲,JavaScript 中每个的函数都是一个闭包,但通常意义上嵌套的函数更能够体现出闭包的特性,请看下面这个例子: var generateClosure = function() { var count = 0; var get

javascript深入理解js闭包(摘自网络)

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. Js代码 var n=999; function f1(){ alert(n); } f1(); // 999 另一方面,在函数外部自然无法读取函数内的局部变量. Js代码 function