闭包的理解

57 阅读2分钟

闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。直观的说就是形成一个不销毁的栈环境。

通常情况下我们在统计一些数值时,使用全局变量,然后调用函数进行统计

var counter = 0; 
function add() { 
   return counter += 1;
} 
add();
add(); 
add();

但是如果这样写的话,页面上的任何脚本在没有调用add()的情况下,也能改变计数器,那么就需要我们将全局变量声明为局部变量,防止在没有调用add()的情况下,修改计数器的值。于是我们会这样写:

function add() {
     var counter = 0; 
     return counter += 1;
   }
add(); 
add(); 
add();

我们会想当然的认为每调用一次add(),计数器就会+1,但其实由于变量在函数内部声明,那么每次调用后都会重新给变量赋值为0,因此上面代码的输出结果会是三个1,而不是1,2,3。

那么我们可能也会写成这样:

function add() { 
  var counter = 0; 
  function plus() {
    counter += 1;
  } 
  plus();
  return counter;
}

通过使用嵌套函数来访问父函数中的局部变量,这样就可以实现对counter的累加了,但是目前还是不够的,因为我们还需要保证这个counter=0只执行一次且函数外部可以访问plus函数,这样就可以解决问题了。

因此我们需要闭包

//闭包的使用
var add = (function () { 
  var counter = 0; 
  return function () {return counter += 1;}
})(); 
add(); 
add(); 
add();

我们通常会想当然的认为每次调用 add() 都会重走一遍add()中的代码块, 但其实不然。

注意add方法中的return, 它return的并不是1,2,3这样的数值,而是return了一个方法,并且把这个方法赋值给了add变量。

那么在这个function自运行一遍之后,其实最后赋值给add的是return counter += 1 这段代码。

所以后面每次调用add() 其实都是在调用return counter += 1。

闭包会持有父方法的局部变量并且不会随父方法销毁而销毁, 所以这个counter其实就是来自于第一次function执行时创建的变量。