JavaScript中的作用域和闭包
作用域是什么
作用域:是代码中定义变量的区域。它规定了哪些区域存储了变量,以及如何去查找这些变量。比如说,下面这段代码,在输出a
的时候,会在函数foo
的作用域中去查找a
的值,然后输出。
function foo() {
var a = 1;
console.log(a); // 1
}
词法作用域和动态作用域
作用域分为词法作用域和动态作用域。
- 词法作用域
词法作用域:在函数的定义时,函数作用域就已经确定了。JavaScript
中使用的就是词法作用域。 - 动态作用域
动态作用域:函数的作用域是在运行时确定的。看个简单的栗子:
function foo() {
console.log( a ); // 词法作用域输出的是 2,动态作用域输出的是 3
}
function bar() {
var a = 3;
foo();
}
var a = 2;
bar();
作用域链
先看段代码:
在全局作用域中:有 foo ;
在函数作用域 1 中:有 a、b、bar ;
在函数作用域 2 中:有 a、b、c ;
运行时,引擎会从当前变量引用处的作用域,一层一层向上查找变量。比如说,上面这段代码,引擎在执行console.log()
时,首先在函数作用域 2 (bar
)中查找变量a、b、c
的值,在当前作用域中,没有发现a
的值,会从上一层作用域(foo
)中查找a
的值,在这里找到了a
的值,然后就使用了a
的值。变量b
和c
同理,也是一层一层向上查找,直到找到全局作用域为止。一旦找到第一个匹配,作用域查询就停止了。
闭包
闭包:有权访问另一个函数作用域内变量的函数;
function foo() {
let a = 2
}
先看这段代码,在函数foo
的作用域中有个变量a = 2
,如果有个函数bar
能够访问函数foo
中的变量a
,那函数bar
就是个闭包。说的简单,怎么才能让函数bar
能够访问到函数foo
中的变量a
呢。确实很简单,在函数foo
中我们返回一个函数,这个函数引用了变量a
就可以了。
function foo() {
let a = 2
return () => {
console.log(a)
}
}
const bar = foo()
bar() // 2,bar是个闭包