【JavaScript】从作用域角度理解闭包

作用域类型

在 JS 世界中,目前已经有了三种作用域:
全局作用域
函数作用域
块作用域
○ 由let或者const声明的变量,如果被一个大括号 {}这样括住了,那么这个大括号就是一个代码块,大括号括住的这些变量就形成了一个块作用域

一个简单的语句:

var a = 1;

在js引擎中执行上述语句分为两个阶段(一边编译一边运行):
var a ===》 编译时声明
a = 1 ===》 运行时赋值
在运行时js引擎会找当前作用域下是否有a的声明,没有的话就会往上级作用域查找,一直到最外层全局作用域还没有的话会抛出异常。

作用域链

当一个块或者一个函数嵌套在另一个块或者函数中时,就发生了作用域的嵌套。比如这样:

function addA(a) {
    
    
  console.log(a + b)
  console.log(c) // 报错
}

var b = 1

addA(2) //3

在这个例子中,有两个作用域:addA 的函数作用域和全局作用域。它们的关系示意如下:

在这个查找过程中,层层递进的作用域,就形成了一条作用域链

闭包

函数使用了既不是函数参数也不是当前作用域的变量就构成了闭包。

const test = (()=> {
  let a = 1;
  return () => {
    return a++;
  }
})()

 console.log(test(), test())// 1 2

如上面例子,当test函数内使用a变量时发现对应函数作用域下并没有,然后沿作用域链往上找,找到对应函数作用域外有然后使用,此时便构成了闭包。