困惑了很久的闭包(closure)

Posted 奥特曼 

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了困惑了很久的闭包(closure)相关的知识,希望对你有一定的参考价值。

一、什么是闭包

MDN

一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在 javascript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。

    let a = "奥特曼"
    function fn() {
      console.log(a); //奥特曼
    }

通过MDN来看 你可以理解为上面就是一个闭包  下面三行概念是一个意思  

1.   函数 + 周围状态(环境的)的引用 = 闭包

2.「函数」和「函数内部能访问到的变量」(也叫环境)的总和,就是一个闭包。

3. 执行函数是f+a构成的结果就是闭包

通过这三个同样的概念 也是让我对闭包有了更新的概念   

在之前理解的是有权访问另一个作用域的函数叫闭包,当然这句话和上面三个理解其实也没什么太大区别,但是之前一直以为是函数嵌套形式

    function fn() {
      var a = "奥特曼"
      return function () {
        console.log(a)
      }
    }
    let a = fn()
    a()

误区①

上面是一个闭包确实没错,但是不能肯定只有嵌套这一种形式才叫做闭包,嵌套只不过是大部分情况,我同样可以不写return  不去接收调用接收fn函数的值,他只是没有被我调用,但他还是一个闭包结构。所以记住这一点,写return只是为了去接收它,并不影响他是闭包。同样我也可以把这个函数挂载到window下,同样可以访问到数据

    function fn() {
      var a = "奥特曼"
       function fn2() {
        console.log(a)
      }
      window.test=fn2
    }
    fn()  
    window.test()

误区②

调试工具的closure

不知道你们有没有这个疑惑,在之前学习都会发现闭包在断点调试的时候都会产生一个Closure 是不是调试一遍没有发现closure他就不是闭包了,其实也不能这么理解,就像十几年前的Chrome可能都不会出现Closure,当然出不出现我也不知道哈哈,而在断点调试什么时候出现Closure 是必须在函数调用或者return的时候才会出现

二、闭包的作用

封闭数据,提供操作

函数的运行机制是 调用=》销毁  在函数外部是调用不到的 而利用了闭包的技术可以在外部对变量进行操作

在JavaScript中 变量的作用域无非就全局变量域和局部变量,在使用变量的时候,函数内部可以访问函数外部的作用域变量,而函数外部访问不到函数内部的作用域变量

① 函数内部读取外部作用域变量(当然这也是闭包)

    let a = "奥特曼"
    function fn() {
      console.log(a); //奥特曼
    }
    fn() 

② 外部作用域读取函数内部变量

    function fn() {
      let a= "奥特曼"
    }
    console.log(a);  //a is not defined

如果说你不理解作用域 先去 看  全局作用域和局部作用域

通过上面代码来看 外部是拿不到函数内部的变量,这时候就用到了闭包

 闭包让你可以在一个内层函数中访问到其外层函数的作用域,来把这句话拆分成代码的形式就是子函数访问了父函数作用域的变量就形成了闭包 

    function fn() {
      var a = "奥特曼"
      function fn2() {
        console.log(a);
      }
      fn2()
    }
    fn()

看过上面的例子 我们再来看下一个特性

     function outerFn() {
      var i = 0;
      i++
      console.log(i);
    }
    outerFn() //1 
    outerFn() //1
    outerFn() //1

函数是在进行不断的创建销毁 创建销毁


    function outerFn() {
      var i = 0;

      function innerFn() {
        i++;
        console.log(i);
      }
      return innerFn;
    }
    var inner = outerFn(); 
    inner();  //1
    inner();  //2
    inner();  //3
    var inner2 = outerFn();
    inner2(); //4
    inner2(); //5
    inner2(); //6

特性

闭包可以让这些变量一直在内存中存在,不会随着函数的销毁而进行销毁

每次外部函数执行的时候,都会开辟一块内存空间,外部函数的地址不同,都会重新创建一个新的地址

关于内存泄漏:

内存泄漏指的是 再也访问不到的内存,依旧占着内存空间,我们就是用闭包去访问的数据并不是闭包造成了内存泄漏

关于为什么使用闭包:

你也可以利用闭包 读取函数内部作用域的变量

闭包无处不在!当你再用函数引入外部环境变量的时候,你已经用了闭包,只是你没有注意到!  这句话重点哦!!

以上是关于困惑了很久的闭包(closure)的主要内容,如果未能解决你的问题,请参考以下文章

心态崩了,学了很久的性能测试,面试官说:就这?!

VS2015装上了但是显示成这样,等了很久就是进不去,求大神指导,win7,其他版本还没试过

mac常用软件,自用找了很久的分享一下相信很多人需要

找了很久的网上唯一的一套JVM底层Hotspot源码视频,免费送!

迟来的2020年度总结,顺带附上被鸽了很久的自我介绍

荒废了很久的java以及微信公众平台今天拿起来看了看:这里有很好的教程