闭包程序员程序猿阵线联盟-汇总各类技术干货

闭包不过如此

2018-03-24  本文已影响243人  浪里行舟

引子

闭包,是 javascript 中很重要的一个概念,几乎每次面试都会被问及,然而却是晦涩难懂,令面试者无所适从。本文尽可能用简单易懂的话,讲清楚闭包的概念及其常见的面试题。
我们先来看一个例子:

     function outer(){
          var a = 888;
            function inner(){
                console.log(a);
            }
        }
        inner();//报错

inner这个函数不能在outer外面调用,因为outer外面没有inner的定义,然而如果我非要让inner函数在作用域外执行,该怎么修改上述代码?


本文框架图

闭包是什么

我们可以对上面代码进行如下修改:

   function outer(){
    var a = 888;
    function inner(){
    console.log(a);
    }
    return inner;   //outer返回了inner的引用
    }
    var inn = outer();  //inn就是inner函数了
    inn(); //执行inn,全局作用域下没有a的定义,
         //但是函数闭包,能够把定义函数的时候的作用域一起记住,输出888          

在outer()执行之后,其返回值也就是内部的inner函数赋值给变量inn并调用了inn(),实际上就是通过不同的标识符引用调用了内部函数inner。调用inn()的时候,注意这个调用地点,我们是在outer函数外部调用的inn(),也就是说,在调用的这个地方,根本就不存在a变量的作用域。
但是神奇的是,控制台居然输出了数字1。这就说明了,inner函数能够持久保存自己定义时的所处环境,并且即使自己在其他的环境被调用的时候,依然可以访问自己定义时所处环境的值。

那到底什么是闭包呢?

当函数可以记住并访问所在的词法作用域,即使函数是在当前词法作用域之外执行,这就产生了闭包。 ----《你不知道的Javascript上卷》
我个人理解,闭包就是函数中的函数(其他语言不能函数再套函数),里面的函数可以访问外面函数的变量,外面的变量的是这个内部函数的一部分。

闭包的特性

每个函数都是闭包,每个函数天生都能够记忆自己定义时所处的作用域环境。把一个函数从它定义的那个作用域,挪走,运行。这个函数居然能够记忆住定义时的那个作用域。不管函数走到哪里,定义时的作用域就带到了哪里。接下来我们用两个例子来说明这个问题:

//例题1
var inner;
function outer(){
var a=250;
inner=function(){
alert(a);//这个函数虽然在外面执行,但能够记忆住定义时的那个作用域,a是250
  }
}
outer();
var a=300;
inner();//一个函数在执行的时候,找闭包里面的变量,不会理会当前作用域。
//例题2
function outer(x){
  function inner(y){
  console.log(x+y);
  }
return inner;
}
var inn=outer(3);//数字3传入outer函数后,inner函数中x便会记住这个值
inn(5);//当inner函数再传入5的时候,只会对y赋值,所以最后弹出8

闭包的内存泄漏

栈内存提供一个执行环境,即作用域,包括全局作用域和私有作用域,那他们什么时候释放内存的?

function fn(){
var num=100;
return function(){
  }
}
var f=fn();//fn执行形成的这个私有的作用域就不能再销毁了

也就是像上面这段代码,fn函数内部的私有作用域会被一直占用的,发生了内存泄漏。所谓内存泄漏指任何对象在您不再拥有或需要它之后仍然存在。闭包不能滥用,否则会导致内存泄露,影响网页的性能。闭包使用完了后,要立即释放资源,将引用变量指向null。接下来我们看下有关于内存泄漏的一道经典面试题:

 <script>  
  function  outer(){  
  var num=0;//内部变量  
  return  function add(){//通过return返回add函数,就可以在outer函数外访问了。  
  num++;//内部函数有引用,作为add函数的一部分了  
  console.log(num);  
  };  
 }  
  var func1=outer();//  
  func1();//实际上是调用add函数, 输出1  
  func1();//输出2  因为outer函数内部的私有作用域会一直被占用
  var func2=outer();  
  func2();// 输出1  每次重新引用函数的时候,闭包是全新的。
  func2();// 输出2  
 </script>  

闭包的作用

1.使用闭包可以访问函数中的变量。
2.可以使变量长期保存在内存中,生命周期比较长。
3.闭包的函数另外的意义:可以用来实现模块化。请看下面的例子:

var common=(function(){
var name="通用模块";
function initPage(){
alert(name);
return {
initPage2:initPage
})();
common.initPage2();//通用模块
上一篇下一篇

猜你喜欢

热点阅读