javascript之闭包

217 阅读3分钟

1.什么是闭包

首先假设有一个函数a和函数b,b定义在函数a里面

function a(){
    var i=0function b(){
       return i++;
    }
    b();
}

不是闭包的情况下,调用a,a里面调用b,完成工作,变量被收回。

但是现在有一个函数c,它想要调用a里面的变量i,但是i不在c的作用域链中。

闭包的实现是:

a运行,不再立即执行b,而是返回b,也就是将b暴露出来,此时外部的c运行时得到返回的b,从而得到i值。

function a(){
    var i=0function b(){
        return i++;
    }
   return b;
}
var c=a();
c();

这就是闭包:子函数可以使用父函数的局部变量,实现原理就是作用域链(scope chain)

一句重要的话:JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里。

javascript的回收机制决定了a和b执行完之后,函数内部变量会被回收,但是被第三方引用的情况下,不会被回收。

a运行完被释放,但是里面变量i还在被占用,所以不断执行c()会返回不断递增的i。

让c=null或者其他值,可以释放a的引用,让a里面的变量回收。

闭包只存储外部变量的引用,而不会拷贝这些外部变量的值。

注意: 如果运行a()(),第一次返回1,继续运行,不会递增。因为每运行一次a()(),都会执行var i=0,因此不会累加。

更加通俗的解释就是:

在爷爷的环境中执行了爸爸,爸爸中返回了孙子,本来爸爸被执行完了,爸爸的环境应该被清除掉,但是孙子引用了爸爸的环境,导致爸爸释放不了,这一坨就是闭包。

2.为什么用闭包

局部变量是无法共享和长久保存的,全局变量可能造成变量污染,所以希望有一种可以长久保存的变量又不会造成全局污染。

大项目需要模块化,变量私有化,可以用到闭包。

3.闭包特点

占用更多内存,不容易被释放

4.实际使用

  • timer定时器
(function autorun(){
    var x = 1;
    setTimeout(function log(){
      console.log(x);
    }, 10000);
})();
//变量 x 会一直存活到定时器的回调执行或者 clearTimeout() 被调用
  • 事件处理
function addEvent() { 
   var foo = 0; 
   document.getElementById('btn').addEventListener('click', function (e) { 
        console.log(foo++); 
  }); 
} 
addEvent();
//不断点击按钮,会输出不断递增的foo
  • Ajax
(function autorun(){
    var x = 1;
    fetch("http://").then(function log(){
      console.log(x);
    });
})();
//变量 x 将一直存活到接收到后端返回结果,回调函数被执行

5.多层嵌套

分析下面的代码会输出什么

var a = 1 
function f(b) { 
     return function g(c) { 
         return function h(d) { 
             return a + b + c + d 
         } 
     } 
} 
var add2 = f(2) 
var add4 = add2(2) 
var add5 = add2(3) 
var r1 = add4(10) 
var r2 = add5(10) 
console.log(r1,r2);

6.一道闭包面试题

juejin.cn/post/684490…