JS的闭包到底是什么?

208 阅读3分钟

什么是闭包?

闭包的作用是什么?

这两个问题在前端的面试中经常会被问到,但其实很好理解,我们从最简单的开始。

什么是闭包?

var name = 'andy';
function fn(){
  console.log(name);
}

大家来看这三句代码是不是非常熟悉,但是如果我们将其放在一个立即执行函数中其就形成了闭包:

(function(){
var name = 'andy';
window.fn = function(){
   console.log(name);
}
})();
fn();

我们知道此时在控制台会成功输出andy,但是在立即函数外部却是无法访问到name变量的。

我们来仔细想想我们做了什么,我们在一个函数作用域内部创建了一个变量(这个变量是外界无法访问到的),之后我们在这个函数作用域的内部创建了一个方法,在这个方法中使用了变量name,那么我们为了可以在外界使用这个方法我们就暂且将其放在window上,随着这个立即函数的执行,因为name变量被其他的函数进行了调用所以其不会随着函数执行完毕而销毁,从而产生了闭包。

这样我们们便可以根据自己的理解来得出关于闭包的定义:在一个函数作用域内部,如果其内部的变量被其内部的函数所调用,函数作用域,变量,调用变量的函数这三者便构成闭包。从而导致立即函数在执行完后里面的变量并不会立即销毁。

闭包的作用是什么?

接下来我们再来看一个例子:假设父亲给儿子100块的零花钱,但是又怕儿子一次将钱花完,所以要求儿子一次只能花一块钱,为了让儿子一次只能花一块钱父亲做了一个机器,每当儿子需要花钱的时候就去按这个机器会弹出一块钱。于是大家看代码:

function money(){
        let allMoney = 100;
        function subMoney(){
          return allMoney -= 1;
        }
        return subMoney;
      }
      let subMoney = money();
      console.log(`花一次钱,爸爸的钱还剩:${subMoney()}元`);
      console.log(`花一次钱,爸爸的钱还剩:${subMoney()}元`);
      console.log(`花一次钱,爸爸的钱还剩:${subMoney()}元`);

image.png

我们创建了一个方法,这个方法就像父亲给儿子做的那个机器,机器里的钱儿子是无法直接获取到的,儿子只能通过按机器的按钮(调用subMoney)来花钱,这个机器即完成了钱不被别人偷走(变量隐藏),又完成了钱不可以被儿子随意使用的作用(函数调用变量,变量不可以被随意修改)。

所以我们来总结一下闭包的作用:

  • 隐藏变量,利用函数作用域使外界无法直接调用。

  • 变量无法被外界随意修改,利用函数来间接访问变量。

但是大家要注意在这个例子中,我们将subMoney返回出去和闭包并没有半毛钱的关系,我们要始终牢记产生闭包的三个要素**函数作用域,变量,调用变量的函数。**​无论是我们将函数放在window上,还是将函数返回出去都只是为了让外部使用这个函数而已。

image.png

最后:

我们知道一个函数在执行完后其内部的变量会被自动销毁,但是如果我们在另一个函数的内部调用了这个变量,那么为了使函数随时可以调用​这个变量在内存中便不会被回收,所以我们对闭包一定要谨慎使用。

同理如果这函数作用域内还有一个变量,但它没有被任何函数调用,那么在函数执行完后其会被销毁。