闭包的个人理解

165 阅读6分钟

闭包

含义:闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数

作用

  1. 在实际开发中,闭包最大的作用就是用来 变量私有。
  2. 延长父函数变量的生明周期,因为js中只要变量后期不被调用,那么就得回收

闭包的三个特性

  1. 子函数可以访问父函数的变量行为
  2. 可以延长被调用父函数变量的生命周期
  3. 可以扩展父函数的空间

闭包会形成作用域

分为三种类型:全局作用域;函数作用域;块作用域。

全局作用域

  1. 全局作用域在页面打开的时候创建,在页面关闭时销毁。
  2. 直接写在script标签的JS代码,都在全局作用域。在全局作用域下声明的变量叫做全局变量(在块级外部定义的变量)。
  3. 全局变量在全局的任何位置下都可以使用;全局作用域中无法访问到局部作用域的中的变量

函数作用域又称(局部作用域)

  1. 在函数作用域中可以访问全局变量,在函数的外面无法访问函数内的变量。
  2. 当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用,如果没有就向上一作用域中寻找,直到找到全局作用域,如果全局作用域中仍然没有找到,则会报错
  3. 调用函数时会创建函数作用域,函数执行完毕以后,作用域销毁。每调用一次函数就会创建一个新的函数作用域,他们之间是相互独立的。

块作用域

  1. ES6之前JavaScript采用的是函数作用域+词法作用域,ES6引入了块级作用域
  2. 任何一对花括号{}中的语句集都属于一个块,在块中使用let和const声明的变量,外部是访问不到的,这种作用域的规则就叫块级作用域
  3. 通过var声明的变量或者非严格模式下创建的函数声明没有块级作用域。

优点

  1. 访问其他函数内部变量
  2. 变量长期驻扎在内存中,不会被内存回收机制回收,即延长变量的生命周期;
  3. 避免定义全局变量所造成的污染

缺点

  1. 大量使用闭包,造成内存占用空间增大,有内存泄露的风险

闭包内存泄漏

含义:就是当已经不需要某块内存时这块内存还存在着,垃圾回收机制就是间歇的不定期的寻找到不再使用的变量,并释放掉它们所指向的内存。

存在内存泄漏问题

  1. 闭包函数导致的泄漏
  2. javaScript对象泄漏
  3. BOM / DOM对象泄漏

解决内存泄漏问题

  1. (不用循环)解除循环引用
  2. 将闭包引用的外部函数中活动对象清除
  3. js的垃圾回收机制就是为了防止内存泄漏的

在vue中解决内存泄漏

  1. 如果组件中使用了定时器,需要在beforeDestroy 中做对应销毁处理
  2. 如果在mounted/created 钩子中使用了第三方库初始化,需要在beforeDestroy 中做对应销毁处理
  3. 如果在mounted/created 钩子中绑定了DOM/BOM 对象中的事件,需要在beforeDestroy 中做对应解绑处理
               function fun() {
            var name = "monkey";
             console.log(name, 123);
            function fun1() {     //他是个闭包函数
                console.log(name, 111);//它可以访问到函数外部的变量  var name = "monkey";
                //调用了 var name = "monkey";因为子函数调用了父函数的变量name的声明周期就会延长
                //如果没有调用name这个变量就会被垃圾回收机制回收 这个就是js变量回收的机制
                //因为产生了闭包所以父函数的内容会变大,因为毕竟里面多调用了一个子函数
                //闭包的特性
                // 1.子函数使用父函数变量行为
                // 2.可以延长被调用父函数变量的声明周期  
                // 3.可以扩展父函数的空间
            }
            return fun1;
        }
        var myFunc = fun();//为什么 var myFunc = fun() fun()赋值给myFun 是因为 fun函数里面有一个子函数fun1所以得赋值
        myFunc();
        //打印的结果是 
            monkey 123
            monkey 111
               function fun() {
            var name = "monkey";
             console.log(name, 123);
            function fun1() {     //他是个闭包函数
                //console.log(name, 111);//它可以访问到函数外部的变量  var name = "monkey";
                //调用了 var name = "monkey";因为子函数调用了父函数的变量name的声明周期就会延长
                //如果没有调用name这个变量就会被垃圾回收机制回收 这个就是js变量回收的机制
                //因为产生了闭包所以父函数的内容会变大,因为毕竟里面多调用了一个子函数
                //闭包的特性
                // 1.子函数使用父函数变量行为
                // 2.可以延长被调用父函数变量的声明周期  
                // 3.可以扩展父函数的空间
            }
            return fun1;
        }
        var myFunc = fun();//为什么 var myFunc = fun() fun()赋值给myFun 是因为 fun函数里面有一个子函数fun1所以得赋值,
        myFunc();
        //打印的结果是 
            monkey 123    fun1函数没有调用 var name = "monkey",应该是会被销毁的但是fun函数还是打印monkey 123,应为js的执行机制是从上往下执行的执行完fun函数有执行了fun1函数
               function fun() {
            var name = "monkey";
             console.log(name, 123);
            function fun1() {     //他是个闭包函数
                //console.log(name, 111);//fun1里面可以访问到函数外部的变量  var name = "monkey";
                //调用了 var name = "monkey";因为子函数调用了父函数的变量name的声明周期就会延长
                //如果没有调用name这个变量就会被垃圾回收机制回收 这个就是js变量回收的机制
                //因为产生了闭包所以父函数的内容会变大,因为毕竟里面多调用了一个子函数
                //闭包的特性
                // 1.子函数使用父函数变量行为
                // 2.可以延长被调用父函数变量的声明周期  
                // 3.可以扩展父函数的空间
            }
            return fun1;
        }
 fun()   //如果直接调用fun()就没有办法打印到fun1里面执行的内容,所以只打印了fun()函数里面的内容
        //打印的结果是 
            monkey 123