闭包-知道这些就够了

167 阅读3分钟

闭包一直是对小白一个比较困扰的问题,小编这边也是再次复习了一下然后整理了一下跟大家一起分享一下。


js回收机制

代码的运行是依赖于内存的,我们声明的任何变量都需要消耗内存,这些变量越多运行的速度也会越慢,代码回收规则如下:

  • 全局变量不会被回收。

  • 局部变量会被回收,也就是函数一旦运行完以后,函数内部的东西都会被销毁。

  • 只要被另外一个作用域所引用就不会被回收

变量作用域

变量的作用域无非就是两种:全局变量和局部变量。当函数执行时会产生一个执行期上下文(也就是我们在预编译中一直称之的AO对象,全局执行上下文也会生成一个AO对象),函数如果多次执行那么所生成的是独一无二的执行上下文对象,当函数执行完该AO对象就会销毁。当函数嵌套时就会产生作用域链,那么当函数内返回嵌套的函数到外部调用时,回收机制就会有一些改变。

    function number() {
        let sum = 0;
        return sum;
    }
    
    let sum1 = number();
    console.log(++sum1); // 1 
    
    let sum2 = number();
    console.log(++sum2)  // 1

闭包

闭包产生的原因上面已经提及到了,闭包实现了函数内部和函数外部的链接,js特殊的点就在于函数内部可以引用全局变量,那么先说一下他的三个特性:

  • 函数内嵌套函数

  • 函数内部可以引用外部参数和变量

  • 参数和变量(AO)不会被回收机制回收

function makeAdder(x) {
  let a = '外部函数变量'
  return function(y) {
    return x + y + a;
  };
}

var add5 = makeAdder(5);
var add10 = makeAdder(10);

console.log(add5(2));  // '7外部函数变量'
console.log(add10(2)); // '12外部函数变量'

当函数回调产生闭包时,函数调用结束AO对象不会消除掉,所以闭包函数还是可以访问到嵌套他函数的变量

循环产生闭包

这个问题可以说是闭包最经典的案例

    function test() {
        let arr = [];
        for(var i = 0; i < 10; i++) {
            arr[i] = function() {
                console.log(i);
            }
        }
        return arr;
    }
    var arr1 = test();
    for(var j = 0; j < 10; j++) {
        arr1[j]();
    }

我们可以这样去理解这个案例函数定义不执行时编译器是不会进去看他内部的代码,而当我们执行回调时test函数AO对象的i为10,所以输出十个10。

解决方法:

  • 立即执行函数

    将循环内部操作套上一层立即执行函数那样每一步循环都会进去

  • let定义循环i var 初始变量在for循环体内,是覆盖式的,用C的话来讲是共用体,即共用同一内存地址,let初始变量在每一次for循环中,都是一个独立的变量,拥有自己独立的内存地址。这一点也是我们要去理解的。

end...