最近在看控制台
的时候,突然发现一个神奇的内部属性[[Scopes]]
这勾起
了我对作用域
的深深
回忆:
- 每个
函数
都有自己的作用域
,作用域
中包含了该函数
声明的所有顶层变量
函数
可以访问上层
的作用域
,也就是说,当查找变量时,如果执行的函数本身
没有这个变量
,那就会向上查找,直到全局作用域
,这样就形成了作用域链
作用域
是静态词法作用域
,也就是说在函数声明
时就已经确定了
实际上,在早前,查看作用域
只能在调试时
查看,例如:
let c = 1;
function a() {
let d = 1
return ()=> {
let e = 1;
console.log(c)
console.log(d)
debugger
}
}
可以看到这里有四个属性
:
先简单的介绍一下这几个属性:
- Local:就是
当前执行函数
的顶层变量
,注意是顶层变量
,这里就是e
,块级作用域的变量
实际上是用另一个表示----Block
- Closure:归类为
闭包
的变量,也就是a函数
中的b
- Script:
全局脚本变量
,这里可以看到我们声明的c
- Global:
全局window对象
当然这一定要在调试
的时候查看。但是,现在有了更加快捷的方式,就是用[[Scopes]]
,重新组织刚才的代码:
let c = 1;
function a() {
let d = 1
return function f() {
let e = 1;
console.log(c)
console.log(d)
console.dir(f) // 输出f函数
}
}
可以看到几乎输出了一样的输出,只是没有Local
,当然为什么没有Local
,主要是函数
没运行
,所以只能确定静态词法作用域
,所以这里又对应上了静态词法作用域
。
当然既然看到了Closure
,这就不得不提到作用域
的一种特殊形式闭包
,先来简单回忆一下闭包(Closure)
:
1.闭包(Closure)
就是函数
携带其它函数作用域
的一种形式
这里有一点要注意,闭包
是函数
和函数
之间存在的,来一个例子佐证:
function a() {
{
let d = 2;
function b() {
console.log(d);
console.dir(b);
debugger ;
}
b()
}
}
可以看到函数b
引用了上层块级作用域
的变量,但是没有闭包(Closure)
所以[[Scopes]]
这个内部属性
,还是非常有用的,不过目前的御三家
,火狐
是没有的: