1.创建函数

    • 开辟一个堆内存
    • 把函数体中的代码当做字符串存储进去
    • 把堆内存的地址赋值给函数名/变量名
    • 函数在哪创建的,那么它执行的时候需要查找上级作用域是谁

    2.函数执行

    • 形成一个全新的私有作用域(执行一次形成一个,多个之间不会产生影响)
    • 形参赋值&变量提升
    • 代码执行(把所属堆内存中的代码字符串拿出来一行行执行)
    • 遇到一个变量,首先看它是否为私有变量(形参和在私有作用域中声明的变量是私有变量)是私有的就操作自己变量即可,不是私有的则向上级作用域中查找,,一直找到全局作用域为止=>作用域链查找机制
    • 私有变量和外界的变量没有必然关系,可以理解为被私有占内存保护起来了,这种机制其实就是 闭包保护机制

    3.关于堆栈内存释放问题
    函数执行就会形成占内存(从内存中分配的一块空间,)如果内存都不销毁释放,很容易就导致内存溢出(内存爆满,电脑卡死了)堆栈内存的释放问题是学习JavaScript的核心知识之一

    • 堆内存释放问题

      1. // 创建一个引用类型值,就会创建一个堆内存
      2. // 如果当前创建的堆内存不被其他东西所占用,浏览器就会在空闲的时候,查找每一个内存的引用状况,不被占用的都会回收释放掉
      3. let obj = {
      4. name:'anjing'
      5. };
      6. let oop = obj;
      7. // 此时obj和oop都占用对象的堆内存,想要释放堆内存,需要手动解除变量和值的关联(null:空对象指针)
      8. obj = null
      9. oop = null
    • 栈内存释放 ```javascript // 打开浏览器形成的全局作用域就是栈内存 // 手动执行函数形成的私有作用域就是栈内存 // 基于es6的let const 形成的块级作用域也是栈内存

    // 全局栈内存:关掉页面的时候才会销毁 // 私有栈内存:一般情况下,函数只要执行完成,形成的私有栈内存就会被销毁释放掉 2.但是一旦栈内存某个东西(一般都是堆地址)被私有作用域意外的事物占用,则当前的私有栈内存不能立即被释放销毁,特点:私有作用域的私有变量等信息也保留起来了 // 市面上认为的闭包是:函数执行形成不能被释放的私有栈内存,这样才是闭包 function fn() { //… } fn() // 函数执行形成栈内存,执行完成栈内存销毁

    function x() { return function() { //…. } } let f = x() // f占用x执行形成的栈内存中的一个东西,(返回小函数对应的堆,则x执行形成的栈内存不能被释放了

    1. **闭包的两个作用** <br />从性能角度讲,我们真实项目中应该减少对闭包的使用,(因为闭包会产生不释放的栈内存,过多使用容易导致内存溢出或者减低性能)
    2. - 保护
    3. - 保存
    4. 1.jQuery 前端非常经典的类库:提供了大量的方法供开发人员使用<br />=>为了防止全局变量污染(解释:导入JQ后,它里面有大量的方法,如果这些方法不保护起来,用户编写的方法很容易和JQ方法相同产生冲突,产生冲突可以理解为全局变量污染,)JQ的方法和变量需要闭包来保护起来。<br />在真实项目中,我们一般把自己写的内容放到一个闭包中,这样可以有效防止自己的代码和别人代产生冲突(全局变量污染:真实项目要尽可能减少对全局变量的使用,);如果需要把自己的东西给别人用,基于return window.xxx等方式暴露给别人即可
    5. ```javascript
    6. //原生js
    7. var xxx(function (){
    8. //自己的代码
    9. return xxx;
    10. })()