后端转前端之上下文及作用域到闭包

这部分内容其实我也是还是一知半解.我先分享一个有意思的例子.

    function F1() {
      a = 50;
      var b = 500;
      return function F2() {
        console.log(a, b, c);
      };
    }
    var fn = F1();
    var a = 100;
    var b = 1000;
    var c = 10000;
    fn();

请问输出值是什么?
100 500 10000
为什么是100,500,10000?
我们得先从闭包说起.闭包是什么?网上很多解释,其实闭包的定义很简单:闭包就是能够读取其他函数内部变量的函数.
啥意思?看不懂,看不懂就对了.OK,直白点说,我们的F2函数里没有定义abc,但是我们却能打印出来,这就是闭包相对于正常函数就是.

    var a = 100;
    var b = 200;
    var c = 300;
    function F1(a, b, c) {
      console.log(a, b, c);
    }
    F1(a, b, c);

如果是这样的函数,大家一定脱口而出,100 200 300,为什么?
因为这个函数把a,b,c的值传进去了.
但是现在有个问题,怎么样才能形成闭包呢?
这里需要引入一个新知识点,作用域.
作用域就是你可以理解为环境.什么意思呢?就以上面的为例.
我们的var a = 100,b=200,c=300这些代码在全局作用域中,而console.log(a,b,c)在函数F1的局部作用域中.如果我们let a = 100,这时候会形成一个块级作用域.这块咱们暂时不用考虑.
如果某个函数要使用自己没有声明的变量,这时候回去声明这个函数的作用域中寻找,如果还是没有就会再往上寻找.
那我们回到初始的例子.

    function F1() {
      a = 50;
      var b = 500;
      return function F2() {
        console.log(a, b, c);
      };
    }
    var fn = F1();
    var a = 100;
    var b = 1000;
    var c = 10000;
    fn();

a的值变化过程是怎么样的?
想要知道a的值是怎么变化的,首先我们要知道这几行代码的运行顺序.全局环境下,先运行了var fn = F1(),然后对a,b,c赋值,然后执行fn();
运行F1()时,把全局中的a赋值成了50(此前a=undefined,因为js会将变量声明提前.并且这里是一个闭包),并在函数作用域里定义了b为500.
对全局作用域下的a,b,c赋值.此时有4个变量.
全局作用域:a = 100,b = 1000,c = 10000
F1作用域:b = 500
然后执行fn(),相当于执行F2(执行F1函数的返回函数).
此时我们的F2函数作用域里是没有a,b,c的.
此时往声明F2的作用域–F1中寻找,这里有b=500,a,c还是没有,这时候往声明F1的作用域–全局中寻找,a = 100,c=10000.那么输出的时候就是100,500,10000了.这时候聪明的小朋友就又有了一个疑惑.

    function F1() {
      var a = 100;
      console.log(a);
    }
    F1();
    console.log(a);

这样输出的值是什么?
100 和 报错.因为F1函数执行完就没他什么事了.全局中没有定义a,那么这里浏览器就会报a未定义.
在这里插入图片描述
所以闭包只会由内而外去寻找,而不会由外而内去寻找.

    function f1() {
      var n = 999;
      nAdd = function () {
        n += 1;
      };

      function f2() {
        console.log(n);
      }

      return f2;
    }
    var result = f1();
    result(); //999
    nAdd();
    result(); // 1000

    f1()();//999
    nAdd();
    f1()();// 999
	

闭包还有一个作用可以在这个例子里显现出来,就是使你定义再函数内部的变量不会被销毁.
例如上面例子中的f1中的n,正常我们在执行完函数之后会gc回收掉,如果跟我一样是后端转前端的同学应该知道垃圾回收器这个东西.就像我们的桌子上本来是空的,需要打草稿计算1+1的时候会拿一张草稿纸写写画画,当我们打完草稿,算出来1+1=2的时候,这张草稿纸就对我们没用了,接下要算2+2等于几了,这时候这张算1+1=2的草稿纸我们就要把它扔到垃圾桶里.这就是垃圾回收的基本原理了.那如果这张草稿纸我们以后还想看看,或者草稿纸上面记录了类似5月14号是晴天之类的别的东西在里面,我们不想把他扔掉.这时候我们就需要形成一个闭包.那么这时候闭包就是我们在算2+2,3+3的时候,还能取出草稿纸看5月14号是晴天,然后把2+2这张草稿纸上也写上5月14号是晴天.

讲这么多,其实对应到上面的例子就是var result = f1()这行代码形成了一个闭包,nAdd()将f1作用域中的n++,之后再result()的时候,我们又可以取出n的值了.而下面 f1()()在运行完之后就已经被销毁了,没有别的地方引用,也没有别的地方可能用到,那就是一张无用的草稿纸,就被回收了.
那么草稿纸要是每页都留着就会占用我们的桌子,让我们没地方放别的东西.所以闭包也有可能会引起内存写漏.这是闭包的缺点.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值