Skip to content
前端

闭包

杨少侠

820字约3分钟

前端

2022-9-15

闭包

词法作用域(Lexical scope)

一个函数可以访问在它的调用上下文中定义的变量,这个就是词法作用域(Lexical scope)

局部变量

局部变量,就像函数的私有财产,局部变量只能在定义它的函数内使用

局部变量

但是,子函数可以直接使用父函数的局部变量

function fn1() {
  let str = 'Blue真帅';

  function fn2() {
    alert(str); //正常弹出
  }

  fn2();
}

fn1();

垃圾回收

function show() {
  //我们有一个局部变量a
  let a = '欢迎大家阅读blue的教程,如果喜欢,请点赞,谢谢';
}

//粗略的分为三个阶段:

//1.show执行前:a是不存在的,不占空间
show(); //2.show执行时:a被分配空间
//3.show结束后:a的生存周期结束,可以被回收

局部变量(通常)在函数执行后,就会被回收(当然,变量其实并没有被立即回收,而是被标记为“可回收”,在下一次GC工作时被带走)

官方说法:闭包就是指有权访问另一个函数作用域中的变量的函数

function show() {
  let str = '欢迎观看blue的教程';

  document.onclick = function() {
    alert(str);
  };
}

//执行前,str不存在
show(); //执行时,str被创建
//执行后,str“本应”被回收

在上面的例子中,我们show中的局部变量str,本应在函数结束后被回收(局部变量在函数结束后被回收),但是实际情况是,不论你10分钟还是1天以后点击页面,这个str都还在,并没有被回收,原因很简单 函数的存在,延长了外层局部变量的生存周期,只要这个onclick函数还在,那么它(onclick函数)外面的局部变量就不会回收。 另外:闭包会保留全部父级变量,不论用没用。

JavaScript中,每个函数都会创建自身的闭包

闭包给了函数访问外部变量的能力

闭包 = 外部变量 + 函数

闭包的作用

可以利用闭包的特性通过创建一个立即执行函数来模拟块级作用域和私有变量

function foo(){
  for(var i = 0; i < 6; i++){
    setTimeout(function (){
      console.log(i);      //  ?
    }, 1000 * i);
  }
}
foo();

结果:每秒一次的频率输出六个6,在for循环结束后,i已经变成6,定时器执行的时候每次都输出6。

function foo(){
  for(var i = 0; i < 6; i++){
    (function(){
      var j = i
      setTimeout(function (){
        console.log(j);      //  ?
      }, 1000 * i);
    })();
  }
}
foo();

我们使用一个 立即执行函数来包含计时器,立即执行函数也会产生一个 函数作用域,在这个作用域里我们再用一个变量j来存放每次循环变量i的值。for循环结束之后,里面的立即执行函数所创建的执行期上下文并不会被立即销毁,因为里面的回调函数并没有运行,这样看来,就形成了闭包。当回调函数执行时,所打印的值便是每一次for循环所保存下来的变量i的值。

What can I say?