首先在了解闭包之前,我们要了解一下环境和作用域
1.环境和作用域
日常生活中我们生活的环境由周边建设如公园,小区,超市构成的。这就构成了环境
在计算机当中环境就是一块内存的数据。
环境是有作用范围的,eg:武汉周边的建设一般只服务武汉生活的人们,这就是作用域。作用域是闭包的基础
环境存在的价值是被需要,当环境不被需要的时候就会被回收
在js中全局的环境是不会被回收的,全局环境在很多时候是被依赖的
1) 函数被执行后里面的环境变量将会从内存中删除。下面函数在每次执行后将删除函数内部的 total 变量。
function count(){
let total=0
}
count()函数在每次执行的时候都会创建一个环境,都会产生一个新的内存地址 【函数没有调用就不会开辟内存空间或者称之为环境】
作用域链只向上查找,找到全局 window 即终止,应该尽量不要在全局作用域中添加变量。
2) 如果子函数被使用时父级环境将被保留
 function mushu () {
    let n = 1
    return function sum () {  // 当有return之后,里面的数据就在一直被使用 就不会被摧毁
      let m = 1
      return function show () {
        console.log(++m) // 2 3 
        console.log('n', ++n) // 2 3 
      }
      show()
    }
  }
  let a = mushu()()
  a()
  a()
// 调用了两次,被外部引用只会数据不会被销毁,所以一直进行了累加函数定义的数据,其作用域是函数及其子函数,子函数中的数据不会向父级进行传递,向父级进行传递,有可能会覆盖父级的数据
3) let/const
使用 let/const 可以将变量声明在块作用域中(放在新的环境中,而不是全局中)
let 块作用域中
var 函数作用域护着
{
	let a = 9;
}
console.log(a); //ReferenceError: a is not defined
if (true) {
	var i = 1;
}
console.log(i);//1
//**************************其他例子**********************
let arr = [];
for (let i = 0; i < 10; i++) {
	arr.push((() => i));
}
console.log(arr[3]()); //3 如果使用var声明将是102.闭包
闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。
直观的说就是形成一个不销毁的栈环境。
闭包可以实现属性的私有化
3.闭包使用
闭包指子函数可以访问外部作用域变量的函数特性,即使在子函数作用域外也可以访问。如果没有闭包那么在处理事件绑定,异步请求时都会变得困难。
- JS 中的所有函数都是闭包
- 闭包一般在子函数本身作用域以外执行,即延伸作用域
eg:1
 let lessons = [
    {
      title: "媒体查询响应式布局",
      click: 89,
      price: 12
    },
    {
      title: "媒体查询响应式布局",
      click: 84,
      price: 120
    }, {
      title: "Flex布局",
      click: 68,
      price: 90
    }, {
      title: "你好呀!!",
      click: 15,
      price: 34
    },
    {
      title: "hello world",
      click: 89,
      price: 67
    }
  ]
  function bwtween (a, b) {
    return function (v) {   // 这里的v 就是数组里面的元素  
      //function (v)这是between函数的子函数 利用闭包特性可以访问到父级的变量
      return v.price >= a && v.price <= b
    }
  }
  console.table(lessons.filter(bwtween(50, 100)));eg2:实现属性私有
// 普通形式 统计函数调用的次数
  let i = 0
  function fn () {
    i++
    console.log(`函数调用了${i}次`)
  }
function count () {
    let i = 0
    function fn () {
      i++
      console.log(`函数调用了${i}次`)
    }
    return fn
  }
  const fun = count()
4.闭包内存泄漏的问题
 function fn () {
    let count = 1
    function fun () {
      count++
      console.log(`函数被调用了${count}次`)  //函数被调用了2次 函数被调用了3次
    }
    return fun
  }
  // res是一个全局变量,代码执行完成之后不会立即销毁,并且res调用了fn函数,fn调用了fun,fun里面使用到了count,count被引用就不会被回收,所以一直存在
  // 此时:闭包引起了内存泄露
  const res = fn()  
  
  res()   
  res()
//注意不是所有的内存泄露都要手动回收,react中的很多闭包不能被回收上级作用域会为函数保存数据,从而造成的如下所示的内存泄漏问题
<body>
  <div desc="annanan~~">周日了</div>
  <div desc="hahahahah!!!">我也不知道!! </div>
</body>
<script>
  let mushu = document.querySelectorAll("div")
  mushu.forEach(function (item) {
    let desc = item.getAttribute("desc")
    item.addEventListener("click", function () { // 这个函数是事件处理函数,是一直存在的,
      // 根据闭包的特性父级作用域的元素也会一直存在,
      console.log(item.getAttribute("desc"))  // getAttribute 属性名
      console.log(item)
    })
  }) 
下面通过清除不需要的数据解决内存泄漏问题
<body>
  <div desc="annanan~~">周日了</div>
  <div desc="hahahahah!!!">我也不知道!! </div>
</body>
<script>
  let mushu = document.querySelectorAll("div")
  mushu.forEach(function (item) {
    let desc = item.getAttribute("desc")
    item.addEventListener("click", function () { // 这个函数是事件处理函数,是一直存在的,
      // 根据闭包的特性父级作用域的元素也会一直存在,
      // console.log(item.getAttribute("desc"))  // getAttribute 属性名
      console.log(desc)
      console.log(item)
    })
    item = null
  })
</script>
5.闭包一定存在内存泄露吗?闭包一定有return?
闭包可能引起内存泄露,但是不一定所以的内存泄露都会被回收
答案是不一定
闭包经常被函数包裹,里面的变量是局部的,外面不能直接使用,所以我们会用到return,将函数返回出去,外部可以使用内部的变量,但是不能修改里面的变量。



















