• javaScript关于闭包的理解


    首先在了解闭包之前,我们要了解一下环境和作用域

    1.环境和作用域

    日常生活中我们生活的环境由周边建设如公园,小区,超市构成的。这就构成了环境

    计算机当中环境就是一块内存的数据。

    环境是有作用范围的,eg:武汉周边的建设一般只服务武汉生活的人们,这就是作用域。作用域是闭包的基础

    环境存在的价值是被需要,当环境不被需要的时候就会被回收

    在js中全局的环境是不会被回收的,全局环境在很多时候是被依赖的

    1)  函数被执行后里面的环境变量将会从内存中删除。下面函数在每次执行后将删除函数内部的 total 变量。
    1. function count(){
    2. let total=0
    3. }
    4. count()

    函数在每次执行的时候都会创建一个环境,都会产生一个新的内存地址 【函数没有调用就不会开辟内存空间或者称之为环境】

    作用域链只向上查找,找到全局 window 即终止,应该尽量不要在全局作用域中添加变量。

    2)   如果子函数被使用时父级环境将被保留
    1. function mushu () {
    2. let n = 1
    3. return function sum () { // 当有return之后,里面的数据就在一直被使用 就不会被摧毁
    4. let m = 1
    5. return function show () {
    6. console.log(++m) // 2 3
    7. console.log('n', ++n) // 2 3
    8. }
    9. show()
    10. }
    11. }
    12. let a = mushu()()
    13. a()
    14. a()
    15. // 调用了两次,被外部引用只会数据不会被销毁,所以一直进行了累加

    函数定义的数据,其作用域是函数及其子函数,子函数中的数据不会向父级进行传递,向父级进行传递,有可能会覆盖父级的数据

    3)    let/const

    使用 let/const 可以将变量声明在块作用域中(放在新的环境中,而不是全局中)

    let 块作用域中

    var 函数作用域护着

    1. {
    2. let a = 9;
    3. }
    4. console.log(a); //ReferenceError: a is not defined
    5. if (true) {
    6. var i = 1;
    7. }
    8. console.log(i);//1
    9. //**************************其他例子**********************
    10. let arr = [];
    11. for (let i = 0; i < 10; i++) {
    12. arr.push((() => i));
    13. }
    14. console.log(arr[3]()); //3 如果使用var声明将是10

    2.闭包

    闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。

    直观的说就是形成一个不销毁的栈环境。

    闭包可以实现属性的私有化

    3.闭包使用

    闭包指子函数可以访问外部作用域变量的函数特性,即使在子函数作用域外也可以访问。如果没有闭包那么在处理事件绑定,异步请求时都会变得困难。

    • JS 中的所有函数都是闭包
    • 闭包一般在子函数本身作用域以外执行,即延伸作用域
    eg:1
    1. let lessons = [
    2. {
    3. title: "媒体查询响应式布局",
    4. click: 89,
    5. price: 12
    6. },
    7. {
    8. title: "媒体查询响应式布局",
    9. click: 84,
    10. price: 120
    11. }, {
    12. title: "Flex布局",
    13. click: 68,
    14. price: 90
    15. }, {
    16. title: "你好呀!!",
    17. click: 15,
    18. price: 34
    19. },
    20. {
    21. title: "hello world",
    22. click: 89,
    23. price: 67
    24. }
    25. ]
    26. function bwtween (a, b) {
    27. return function (v) { // 这里的v 就是数组里面的元素
    28. //function (v)这是between函数的子函数 利用闭包特性可以访问到父级的变量
    29. return v.price >= a && v.price <= b
    30. }
    31. }
    32. console.table(lessons.filter(bwtween(50, 100)));
    eg2:实现属性私有
    1. // 普通形式 统计函数调用的次数
    2. let i = 0
    3. function fn () {
    4. i++
    5. console.log(`函数调用了${i}次`)
    6. }

    1. function count () {
    2. let i = 0
    3. function fn () {
    4. i++
    5. console.log(`函数调用了${i}次`)
    6. }
    7. return fn
    8. }
    9. const fun = count()

    4.闭包内存泄漏的问题

    1. function fn () {
    2. let count = 1
    3. function fun () {
    4. count++
    5. console.log(`函数被调用了${count}次`) //函数被调用了2次 函数被调用了3次
    6. }
    7. return fun
    8. }
    9. // res是一个全局变量,代码执行完成之后不会立即销毁,并且res调用了fn函数,fn调用了fun,fun里面使用到了count,count被引用就不会被回收,所以一直存在
    10. // 此时:闭包引起了内存泄露
    11. const res = fn()
    12. res()
    13. res()
    14. //注意不是所有的内存泄露都要手动回收,react中的很多闭包不能被回收

    上级作用域会为函数保存数据,从而造成的如下所示的内存泄漏问题

    1. <div desc="annanan~~">周日了div>
    2. <div desc="hahahahah!!!">我也不知道!! div>