javascript闭包和立即执行函数的关系(转载)

 一直没搞清楚立即执行函数和闭包之间的关系,总结一下:

  1. 闭包有很多种理解:访问不到内部作用域,函数就是这样,所以函数就是闭包
  2. 闭包还有一种理解:通过把函数内部的变量和方法返回出来,这样外部作用域就可以访问内部作用域了
  3. 立即执行函数和闭包之间没有必然的联系,虽然它们经常结合一起使用;
  4. 立即执行函数只是一种函数的调用方式;
  5. 闭包的目的则是外部函数可以访问内部函数的作用域

立即执行函数(IIFE)

  立即执行函数、立即执行表达式、IIFE(immediately invoked function expression)、自执行函数,叫法不同,都是一样的;

  立即执行函数是指声明完之后便直接执行的函数,这类函数通常是一次性使用的,因此没必要给这类函数命名,直接为匿名函数让它执行就好了;

  主要目的是做的一些封装,防止变量全局污染,以及保证内部变量的安全

  javascript中没有私有作用域的概念,如果在多人开发的项目上,你在全局或局部作用域中声明了一些变量,可能会被其他人不小心用同名的变量给覆盖掉,根据javascript函数作用域链的特性,可以使用IIFE可以模仿一个私有作用域,用匿名函数作为一个“容器”,“容器”内部可以访问外部的变量,而外部环境不能访问“容器”内部的变量,所以( function(){…} )()内部定义的变量不会和外部的变量发生冲突,俗称“匿名包裹器”或“命名空间”。

  JQuery使用的就是这种方法,将JQuery代码包裹在( function (window,undefined){…jquery代码…} (window)中,在全局作用域中调用JQuery代码时,可以达到保护JQuery内部变量的作用。

 

  我们首先需要有函数表达式的概念,点击

 

  javascript只有函数拥有局部作用域,立即执行函数也有这一特点,我们可以利用它减少全局变量造成的空间污染;

<script type="text/javascript">
    (function abc(){
        console.log(abc);//function abc(){...}  
        var a = 1;
        console.log(a);//1
    })()
//    console.log(a); //ReferenceError: a is not defined
    console.log(abc);//ReferenceError: abc is not defined
    //立即执行函数的函数名在外部也是找不到的
    //函数表达式的标识符在外部作用域是找不到的,只有内部作用域可以找到
</script>

 

   

 闭包(closure)

  大牛的讲解,点击

  我们首先需要有作用域的概念,点击

  闭包通常用来创建内部变量,使得这些变量不能被外部随意修改,同时又可以通过指定的函数接口来操作;简单的说,外部作用域就可以访问函数内部作用域的变量了。

  由于作用域的关系,我们在函数外部是无法直接访问到函数内部的变量的,但是函数内部可以把这个变量传给全局变量或者返回出来,这样外部作用域就可以访问函数内部作用域的变量了;

  简单的说,闭包就是有权限访问另一个函数内部作用域的变量的函数;

  1. javascript具有自动垃圾回收机制,函数运行完之后,其内部的变量和数据会被销毁;
  2. 但是闭包就是在外部可以访问此函数内部作用域的变量,所以闭包的一个特点就是只要存在引用函数内部变量的可能,JavaScript就需要在内存中保留这些变量。而且JavaScript运行时需要跟踪这个内部变量的所有外部引用,直到最后一个引用被解除(主动把外部引用赋为null或者页面关闭),JavaScript的垃圾收集器才能释放相应的内存空间;这句话不是很好理解,下面用代码展示;
<script type="text/javascript">
    function outer(){
        var a = 1;
        function inner(){
            return a++;
        }
        return inner;
    }
    var abc = outer();
    //outer()只要执行过,就有了引用函数内部变量的可能,然后就会被保存在内存中;
    //outer()如果没有执行过,由于作用域的关系,看不到内部作用域,更不会被保存在内存中了;
    
    console.log(abc());//1
    console.log(abc());//2
    //因为a已经在内存中了,所以再次执行abc()的时候,是在第一次的基础上累加的
    
    var def = outer(); 
    console.log(def());//1
    console.log(def());//2
    //再次把outer()函数赋给一个新的变量def,相当于绑定了一个新的outer实例;
    
    //console.log(a);//ReferenceError: a is not defined
    //console.log(inner);//ReferenceError: a is not defined
    //由于作用域的关系我们在外部还是无法直接访问内部作用域的变量名和函数名
    
    abc = null;
    //由于闭包占用内存空间,所以要谨慎使用闭包。尽量在使用完闭包后,及时解除引用,释放内存;
</script>

 

  立即执行函数能配合闭包保存状态。

<script type="text/javascript">
    for(var i = 0; i < 3; i++){
          setTimeout(function(){
              console.log(i);    //3 3 3
              //在执行到这一行时,发现匿名函数里没有i,然后向往外部作用域找,然后找到的其实是for循环执行完了的i,也就是2++,3
          },0);  
    };     
    
    
    for(var i = 0; i < 3; i++){
          setTimeout((function(x){
              console.log(x);    //0 1 2
          })(i),0);  
          //在立即执行函数内部i传给了x,并且锁在内存中,所以不会变
    }; 
</script>

 

 

了解完立即执行函数和闭包的关系之后,我们不难看出,立即执行函数和闭包都能没有必然的联系。立即执行函数通过创建一个局部作用域可以防止全局变量污染,保证内部变量的安全,可以减少闭包占用的内存问题(因为没有匿名函数的引用,只要函数执行完毕就可以立即销毁其作用域链)。闭包则是可以从外部访问内部函数的作用域,使得内部变量无需在外部声明也可访问,防止全局变量污染。

 

原文地址:http://www.cnblogs.com/sspeng/p/6623556.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值