一、先理解什么是词法作用域。
词法作用域:
词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的
图片说明

  1. 包含着整个全局作用域,其中只有一个标识符:foo。
  2. 包含着 foo 所创建的作用域,其中有三个标识符:a、bar 和 b。
  3. 包含着 bar 所创建的作用域,其中只有一个标识符:c。

二、闭包
闭包定义:
当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。

e.g.

function foo() {
  var a = 2;

  function bar() {
    console.log( a );
  }

  return bar;
}

var baz = foo();

baz(); // 2 —— 朋友,这就是闭包的效果。

在 foo() 执行后,通常会期待 foo() 的整个内部作用域都被销毁,因为我们知道引擎有垃圾回收器用来释放不再使用的内存空间。由于看上去 foo() 的内容不会再被使用,所以很自然地会考虑对其进行回收。
而闭包的“神奇”之处正是可以阻止这件事情的发生。事实上内部作用域依然存在,因此没有被回收。谁在使用这个内部作用域?原来是 bar() 本身在使用。
拜 bar() 所声明的位置所赐,它拥有涵盖 foo() 内部作用域的闭包,使得该作用域能够一直存活,以供 bar() 在之后任何时间进行引用。
bar() 依然持有对该作用域的引用,而这个引用就叫作闭包。