词法作用域?动态作用域?闭包是如何产生的?

词法作用域

词法作用域就是定义在词法阶段的作用域,就是说跟我们写代码时将变量定义在哪个函数作用域或者块作用域中有关系,大多数情况是不变的(evel/with会修改)image-20220308203325592

图片来自《你不知道的Javascript》

  1. 包含着全局作用域,包括标识符foo
  2. 包含着foo所创建的作用域,包括标识符:a,bar和b
  3. 包含着bar所创建的作用域, 包括标识符c
    无论函数在哪里被调用,它的词法作用域都只有函数被声明时所处的位置决定。

动态作用域

首先我们先了解一下什么是动态作用域,再看闭包与它的区别。

动态作用域就是说当查询标识符的时候不是按照词法作用域嵌套来查找,而是按照调用顺序来查找的, 也就是说 动态作用域不关注你在什么地方声明,它只关心是在何处调用的。

1
2
3
4
5
6
7
8
9
10
11
12
function foo(){
console.log(a)
}

function bar(){
var a = 3
foo()
}

var a = 2

bar() // 3 不是2

事实上输出的是2,JavaScript并不具有动态作用域,它只有词法作用域,简单明了,但是this机制某种程度上很像动态作用域

闭包

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

1
2
3
4
5
6
7
8
9
10
function foo(){
var a = 2
function bar(){
console.log(a)
}
return bar
}

let baz = foo()
baz() // 2

上述代码中foo()执行之后返回一个内部函数bar,然后被赋值给了baz,当baz被调用时实际上就是调用了bar,输出了函数foo作用域中的变量a

无论使用何种方式对函数类型的值传递,当函数在其他作用域被调用时都可以理解为闭包。