《JavaScript高级程序设计》对闭包定义
                    函数本身和该函数声明时所处的环境状态的组合。也就是说,只有权访问另一个函数作用域中变量的函数
                《JavaScript权威指南》对闭包定义
                    函数对象可以通过作用域链相互关联起来,函数体内部变量可以保存在函数作用域内,这就是闭包。

                严格来说,闭包需要满足三个条件:
                    【1】访问所在作用域;
                    【2】函数嵌套;
                    【3】在所在作用域外被调用
                    有些人觉得只满足条件1就可以,所以IIFE是闭包;有些人觉得满足条件1和2才可以,所以被嵌套的函数才是闭包;有些人觉得3个条件都满足才可以,所以在作用域以外的地方被调用的函数才是闭包

                    为什么我们需要闭包,js闭包有什么用处?
 

首先来看一个例子,我们来实现一个计数器。   
  
  <script>
              // 第一种
              let num = 0;
              function add() {
                return (num += 1);
              }
              console.log(add()); // 1
              console.log(add()); // 2
              console.log("全局作用域没有闭包", add()); // 3

              // 现在我们已经达到了目的,可是问题来了,代码中的任何一个函数都可以随意改变num的值,所以这个计数器并不完美。那我们把num放在add函数里面不就好了么?

              // 第二种
              function addNum() {
                let arrNum = 0;
                return (arrNum += 1);
              }
              console.log(addNum()); // 1
              console.log(addNum()); // 1
              console.log("局部作用域 出现问题", addNum()); // 1
              //所以这样做的话,每次调用addNum函数,arrNum的值都要被初始化为0,还是达不到我们的目的。

              // 利用闭包解决问题
 
    第一种:
 
              let addArr = (function () {
                let numberArr = 0;
                return function () {
                  return (numberArr += 1);
                };
              })();

              console.log(addArr());
              console.log(addArr());
              console.log(addArr());
              console.log("闭包第一种方式解决", addArr());
 
   第二种:

              function outerFun() {
                let numberArr = 0;
                function addFun() {
                  return (numberArr += 1);
                }
                return addFun;
              }
              let addOuter = outerFun();
              console.log(addOuter());
              console.log(addOuter());
              console.log(addOuter());
              console.log("闭包第二种方式解决", addOuter());

              // 使用闭包应注意的问题
              // 由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。因此可以手动解除对匿名函数的引用,以便释放内存。
            </script>
 

那什么是内存泄漏呢?

  内存泄漏是值指本应该被垃圾回收机制回收的内存控件由于某种特殊原因没有及时回收,称之为内存泄漏,滥用全局变量和滥用和闭包都会导致内存泄漏。