美文网首页
闭包的一点理解

闭包的一点理解

作者: 郑馋师 | 来源:发表于2019-12-11 23:47 被阅读0次

    闭包

    闭包就是可以让函数访问外部变量的函数,其本质就是一个函数,mdn说“函数与对其状态即词法环境(lexical environment)的引用共同构成闭包(closure)。也就是说,闭包可以让你从内部函数访问外部函数作用域。在JavaScript,函数在每次创建时生成闭包。”
    用mdn上面的例子来讲

    function makeFunc() {
        var name = "Mozilla";
        function displayName() {
            alert(name);
        }
        return displayName;
    }
    
    let myFunc = makeFunc();
    myFunc();
    

    最后运行发现两个都打出了aaa,也就是说闭包的作用域链包含着它自己的作用域,以及包含它的函数的作用域和全局作用域,而且内部函数 displayName() 在执行前,就已经被外部函数返回。原因是:
    JavaScript中的函数会形成闭包。 闭包是由函数以及创建该函数的环境组合而成。这个环境包含了这个闭包创建时所能访问的所有局部变量。在我们的例子中,myFunc 是执行 makeFunc 时创建的 displayName 函数实例的引用,而 displayName 实例仍可访问其作用域中的变量,即可以访问到 name 。由此,当 myFunc 被调用时,name 仍可被访问,其值 Mozilla 就被传递到alert中。

    注意!!!!

    作用域会被保留

    通常,函数的作用域及其所有变量都会在函数执行结束后被销毁。但是,在创建了一个闭包以后,这个函数的作用域就会一直保存到闭包不存在为止。
    eg

    function Add(x) {
      return function(y) {
        return x + y;
      };
    }
    let add5 = Add(5);
    let add10 = Add(10);
    
    console.log(Add5(2));  // 7
    console.log(Add10(2)); // 12
    
    let add5=null
    let add10=null//此时才可以被销毁
    

    从上述代码可以看到add5 和 add10 都是闭包。它们共享相同的函数定义,但是保存了不同的环境。在 add5 的环境中,x 为 5。而在 add10 中,x 则为 10。这时候可以发现里面的那个关于y的函数和其作用域有被保留,直到最后通过 null才 释放了 add5 和 add10 对闭包的引用。
    在javascript中,如果一个对象不再被引用,那么这个对象就会被垃圾回收机制回收;
    如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。

    闭包只能取得包含函数中的任何变量的最后一个值

    eg.

    function Arr(){
    let arr=[]
    for(i=0;i<10;i++){
    arr[i]=function(){
    return i}
    }
    return arr
    }
    
    这里,我们发现 没return i

    也就是说用闭包时候,只能return最后最外面那个值,当Arr执行完毕后,其作用域被销毁,但它的变量对象仍保存在内存中,得以被匿名访问,这时i的值为10。
    要想保存在循环过程中每一个i的值,需要在匿名函数外部再套用一个匿名函数,在这个匿名函数中定义另一个变量并且立即执行来保存i的值。

    function Arr(){
    let arr=[]
    for(i=0;i<10;i++){
    arr[i]=function(num){
    return function(){
    return num
    }
    }(i)
    }
    return arr
    }
    

    这时最内部的匿名函数访问的是num的值,所以数组中10个匿名函数的返回值就是1-10

    闭包中的this对象

    要注意this指向的是函数作用时候的环境,和函数名的环境要分开看。eg

    var name=`window`
    var obj={
    name:`obj`,
    getName:()=>{
    return ()=>{
    return this.name
    }
    }
    }
    console.log(obj.getName()())
    

    在上面这段代码中,obj.getName()()实际上是在全局作用域中调用了匿名函数,this指向了window。


    结果是window而不是obj

    作用

    闭包很有用,因为它允许将函数与其所操作的某些数据(环境)关联起来。这显然类似于面向对象编程。在面向对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。
    因此,通常你使用只有一个方法的对象的地方,都可以使用闭包。
    而且其最最最直观的作用,就是我们可以通过这个方法,把我们的操作封装起来,只留一些外部接口,这样即可以使得后面的代码看起来很简洁,又可以不让别人改动到我们的核心代码。这个被称为‘方法的私有化’。

    缺点

    闭包的缺点:
    比普通函数占用更多的内存。
    解决:闭包不在使用时,要及时释放。
    将引用内层函数对象的变量赋值为null。

    相关文章

      网友评论

          本文标题:闭包的一点理解

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