闭包

作者: BIGHAI | 来源:发表于2017-05-27 12:25 被阅读0次

    每一个函数都有其所处的作用域,如果函数是在作用域之外(对于函数而言,作用域只跟声明时所处的位置有关,跟调用处无关)执行时,此时函数如果能够记住并访问得到自己所在的作用域的话,那么此时便形成了一个闭包。

    看一个简单例子:

    function foo(){
      var a = 2
      function bar(){console.log(a)}//bar函数所处的作用域即foo函数内部块中
      return bar
    }
    var baz = foo()
    baz()//2
    

    通过上面的例子结合自己实际经验,你会发现闭包真的就是无处不在。下面分析一下:当我们通过函数变量baz调用函数的时候,此时调用的便是内存中的bar函数。需要记住的是,尽管是不同的名字,但是对于浅拷贝来说,他们实际上引用的都是同一块内存中的数据,所以说,这里的bar()和baz()是一样的结果,问题是闭包会产生这样一种效果:阻止垃圾回收机制回收foo函数内部块中的某些数据,比如说我们这里要用上的a以及bar函数本身。对于函数而言,他的作用域和调用位置无关,所以说关于闭包的核心点就是:对所需要用的资源的延迟回收。

    下面来两个复习作用域的例子:

    var a = 3
    function foo(){
      var a = 2
      function bar(){console.log(a)}
      return bar
    }
    var baz = foo()
    baz()//2
    

    再看看下面这个例子

    function handle(fun){
        var test = 1
        var num = fun()
        return num+1
    }
    function dowork(){
        var test = 6
        var nm = handle(function ques(){console.log(test);return 1})//6
        console.log(nm)//2
        //var can = ques//ReferenceError,ques is not defined
    }
    dowork()
    //输出结果=>6 2
    

    讨论一下ques函数所处的作用域,猜测一:dowork块;猜测二:handle块。根据运行结果很容易得知,肯定不是handle块。那么是不是dowork块?根据6这个输出结果来看,我们可以得知可能是dowork块,但是既让如此为什么在dowork块里面不能访问得到ques函数呢?这又使得我们怀疑是否是dowork块。经过思考发现,ques函数的作用域的确是dowork块,那么为什么不能再dowork内部访问ques呢?答案是这样的,先举个例子:

    var fun = function bar(){console.log(1)}
    bar()//ReferenceError
    

    就是上面的这种情况,一样的道理,但我们将一个函数声明的代码作为右值赋值的时候,那么函数声明中的那个名字会被编译器给忽略。

    1.循环与闭包

    先看一个经典例子:

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

    分析:运行的结果是——连续输出了10个10,每间隔1s输出一次。但是,我们期望的可不是这样的,我们希望能够输出0123456789,那么问题来了,为什么会导致这个问题呢?答案就是,setTimeout函数的特殊性,延时函数里面的回调函数会在循环结束时才执行。那么你设置的延时时间是0而不是1s,所有的回调函数仍旧是在循环结束时才会执行。而我们这里的回调函数的操作就是输出变量i,由于是循环结束才会开始执行回调函数,所以他们都输出了变量最后的那个值10。
    要解决这个问题有好多办法,这里就介绍最简单的那个,利用let关键字:

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

    当for与let结合时,let声明的变量在每次循环都会被再次声明。第n次声明时所赋的值由第n-1次结束时的值来决定。

    END

    相关文章

      网友评论

          本文标题:闭包

          本文链接:https://www.haomeiwen.com/subject/citqfxtx.html