关于闭包的理解

函数的定义

函数的的执行过程
1.函数的定义
1.1在堆里开辟一个空间
1.2把函数体内所有的代码当作字符串存储在这个空间中
1.3把空间地址赋值给栈里的变量(函数名)
2.函数调用
按照存储的地址找到函数存储的空间
在调用栈(不是栈内存)里再次开辟一个函数执行空间
在函数执行空间内进行 形参赋值
在函数执行空间内进行 与解析
把函数存储空间里的代码复制一份拿到函数执行空间 里面执行
代码全部执行完毕,这个新开辟的函数执行空间销毁

所以当函数调用过多,会报内存不够.

定义在函数内部的变量,
会随着函数执行完毕,函数执行空间的销毁而销毁掉。

一个不会被销毁的函数执行空间

函数的每一次执行会创造一个函数执行空间
当函数内部返回一个 复杂数据类型 的时候, 并且函数外部还有变量在接收
这个函数执行空间不会被销毁

全局作用域对应的栈内存;关闭页面的时候会被销毁;
私有作用域的对应的栈内存;一般情况下,函数执行完成,对应的栈内存就会销毁,
当返回值是一个引用数据类型时,不会被销毁;

闭包

形成闭包的条件
一个不会被销毁的函数执行空间
函数内部 直接 或者 间接 的返回一个函数
内部函数操作(访问、赋值)着外部函数的变量

当三个条件都满足的时候
我们管内部的函数叫做外部函数的 闭包函数

闭包的特点:
1.保护变量私有化
优点:不去污染全局
缺点:外部不能访问,需要闭包函数
2.可以在函数外部访问函数内部的变量
优点:不局限于私有变量
缺点:外部访问需要闭包函数
3.变量的生命周期
优点:变量的生命周期被延长了
缺点:一个不会被销毁的函数空间
致命的缺点:一个不会被销毁的函数空间
内存占用太多,浏览器就崩了,内存溢出,内存泄漏,
闭包慎用

function fn() {
    var num = 100;
    return function a() {
      // 访问外部函数fn的私有变量 num
      // 并且把num的值返回
      return num;
    };
  }
  // 此时 res 接受的是 fn函数内部的a 函数
  // 我们管res或者a 叫做fn的闭包函数
  const res = fn();
  // 拿到函数的私有变量 num
  console.log(res());

  // res存储的不再是fn函数内部返回的函数了
  // fn的执行空间被销毁了
  res = 50;

柯里化函数

一种函数的封装形式
把一个函数的两个参数拆开成为两个函数,每一个函数一个参数
多个参数的时候,把第一个参数单独提取出来
柯里化函数主要为了把参数拆开,主要做的事主要为模块化服务的

 //  封装:使用正则去验证用户名
    function fn(reg, name) {
     return reg.test(name);
     }
  // 使用的时候
    const reg = /[^_]\w{5,11}/;
 const res = fn(reg, "guojing");
 console.log(res);
  //   就这么一点事为什么要封装函数?
  //   在模块开发的时候,每一个模块尽量不向外暴露变量,而是向外暴露函数,返回方法
  //   如果验证别的,每次都要传reg
  / const res2 = fn(reg, "huangrong");
 console.log(res2);

// 换一种方式来写
  // 以闭包的形式进行封装、
    function testName(reg) {
      return function (username) {
        return reg.test(username);
      };
     }
  //  将来我使用的时候
  // res接收的是 函数内部 返回的函数
     const resfn = testName(/[^_]\w{5,11}/);

  //   真正进行代码开发的时候;
     const res3 = resfn("guojing");
     console.log(res3);

用闭包解决循环绑定事件问题

export default function Function08() {
  useEffect(() => {
    const wrapDom = document.getElementById("btnwrap");
    const btns = wrapDom.getElementsByTagName("button");
    // es6 let语法 es6转es5也是用闭包的语法,性能问题
    for (let i = 0; i < btns.length; i++) {
      btns[i].onclick = function () {
        console.log(i);
      };
    }

    function fn(index) {
      return function () {
        console.log("我执行了", index);
      };
    }
    // 用闭包解决循环绑定事件问题
    for (var i = 0; i < btns.length; i++) {
      // btns[i].onclick = fn(i);
      btns[i].onclick = (function (index) {
        // 随着循环,每一次这个自执行函数都会执行掉
        // 这个被return 出去的函数才是事件处理函数呢
        return function () {
          console.log("我执行了", index);
        };
      })(i);
    }
  }, []);

  // 变量提升

  return (
    <div id="btnwrap">
      <button>1</button>
      <button>2</button>
      <button>3</button>
    </div>
  );
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容